]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Ion storm event (#20277)
authordeltanedas <39013340+deltanedas@users.noreply.github.com>
Fri, 27 Oct 2023 02:40:13 +0000 (03:40 +0100)
committerGitHub <noreply@github.com>
Fri, 27 Oct 2023 02:40:13 +0000 (22:40 -0400)
* ion storm event prototype + locale

* add lawsets

* use lawsets, make borgs ion storm targets

* ion storm rule and ion storm target

* lawset prototype

* use lawsets

* update silicon law system to use lawsets and support ion storm event

* new toys

* fix

* more fix

* fixy

* ion storm admin logging

* assigning laws makes borg provide its own laws, other stuff

* 1h reoccurence

* 50% chance

* better call saul

* emagLaws is required

* add announcment audio

* fixy

* family friendly gaming

* fixy

* address reviews

* fixy

* more fixy and no erp

* pro

---------

Co-authored-by: deltanedas <@deltanedas:kde.org>
18 files changed:
Content.Server/Silicons/Laws/SiliconLawSystem.cs
Content.Server/StationEvents/Components/IonStormRuleComponent.cs [new file with mode: 0644]
Content.Server/StationEvents/Events/IonStormRule.cs [new file with mode: 0644]
Content.Shared/Silicons/Laws/Components/EmagSiliconLawComponent.cs
Content.Shared/Silicons/Laws/Components/IonStarmTargetComponent.cs [new file with mode: 0644]
Content.Shared/Silicons/Laws/Components/SiliconLawBoundComponent.cs
Content.Shared/Silicons/Laws/Components/SiliconLawProviderComponent.cs
Content.Shared/Silicons/Laws/SiliconLawPrototype.cs
Content.Shared/Silicons/Laws/SiliconLawsetPrototype.cs [new file with mode: 0644]
Resources/Audio/Announcements/attributions.yml [new file with mode: 0644]
Resources/Audio/Announcements/ion_storm.ogg [new file with mode: 0644]
Resources/Locale/en-US/station-events/events/ion-storm.ftl [new file with mode: 0644]
Resources/Prototypes/Datasets/ion_storm.yml [new file with mode: 0644]
Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml
Resources/Prototypes/Entities/Mobs/Player/silicon.yml
Resources/Prototypes/Entities/Stations/base.yml
Resources/Prototypes/GameRules/events.yml
Resources/Prototypes/silicon-laws.yml

index beb760ec8fd9190a133508f87d6a0f4916e351a1..45c944884e715db32da388978ae0996c0b286fbe 100644 (file)
@@ -50,7 +50,9 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem
         SubscribeLocalEvent<SiliconLawBoundComponent, PlayerSpawnCompleteEvent>(OnPlayerSpawnComplete);
 
         SubscribeLocalEvent<SiliconLawProviderComponent, GetSiliconLawsEvent>(OnDirectedGetLaws);
+        SubscribeLocalEvent<SiliconLawProviderComponent, IonStormLawsEvent>(OnIonStormLaws);
         SubscribeLocalEvent<EmagSiliconLawComponent, GetSiliconLawsEvent>(OnDirectedEmagGetLaws);
+        SubscribeLocalEvent<EmagSiliconLawComponent, IonStormLawsEvent>(OnEmagIonStormLaws);
         SubscribeLocalEvent<EmagSiliconLawComponent, MindAddedMessage>(OnEmagMindAdded);
         SubscribeLocalEvent<EmagSiliconLawComponent, MindRemovedMessage>(OnEmagMindRemoved);
         SubscribeLocalEvent<EmagSiliconLawComponent, ExaminedEvent>(OnExamined);
@@ -93,7 +95,7 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem
         _entityManager.TryGetComponent<IntrinsicRadioTransmitterComponent>(uid, out var intrinsicRadio);
         HashSet<string>? radioChannels = intrinsicRadio?.Channels;
 
-        var state = new SiliconLawBuiState(GetLaws(uid), radioChannels);
+        var state = new SiliconLawBuiState(GetLaws(uid).Laws, radioChannels);
         _userInterface.TrySetUiState(args.Entity, SiliconLawsUiKey.Key, state, (IPlayerSession) args.Session);
     }
 
@@ -104,38 +106,66 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem
 
     private void OnDirectedGetLaws(EntityUid uid, SiliconLawProviderComponent component, ref GetSiliconLawsEvent args)
     {
-        if (args.Handled || HasComp<EmaggedComponent>(uid) || component.Laws.Count == 0)
+        if (args.Handled || HasComp<EmaggedComponent>(uid))
             return;
 
-        foreach (var law in component.Laws)
-        {
-            args.Laws.Add(_prototype.Index<SiliconLawPrototype>(law));
-        }
+        if (component.Lawset == null)
+            component.Lawset = GetLawset(component.Laws);
+
+        args.Laws = component.Lawset;
 
         args.Handled = true;
     }
 
+    private void OnIonStormLaws(EntityUid uid, SiliconLawProviderComponent component, ref IonStormLawsEvent args)
+    {
+        if (HasComp<EmaggedComponent>(uid))
+            return;
+
+        component.Lawset = args.Lawset;
+
+        // gotta tell player to check their laws
+        NotifyLawsChanged(uid);
+
+        // new laws may allow antagonist behaviour so make it clear for admins
+        if (TryComp<EmagSiliconLawComponent>(uid, out var emag))
+            EnsureEmaggedRole(uid, emag);
+    }
+
     private void OnDirectedEmagGetLaws(EntityUid uid, EmagSiliconLawComponent component, ref GetSiliconLawsEvent args)
     {
         if (args.Handled || !HasComp<EmaggedComponent>(uid) || component.OwnerName == null)
             return;
 
-        // Add the first emag law
-        args.Laws.Add(new SiliconLaw
+        if (component.Lawset == null)
         {
-            LawString = Loc.GetString("law-emag-custom", ("name", component.OwnerName)),
-            Order = 0
-        });
+            // Add new emagged laws
+            component.Lawset = GetLawset(component.EmagLaws);
 
-        // Add new emagged laws
-        foreach (var law in component.EmagLaws)
-        {
-            args.Laws.Add(_prototype.Index<SiliconLawPrototype>(law));
+            // Add the first emag law before the others
+            component.Lawset.Laws.Insert(0, new SiliconLaw
+            {
+                LawString = Loc.GetString("law-emag-custom", ("name", component.OwnerName)),
+                Order = 0
+            });
         }
 
+        args.Laws = component.Lawset;
+
         args.Handled = true;
     }
 
+    private void OnEmagIonStormLaws(EntityUid uid, EmagSiliconLawComponent component, ref IonStormLawsEvent args)
+    {
+        if (!HasComp<EmaggedComponent>(uid))
+            return;
+
+        component.Lawset = args.Lawset;
+
+        // gotta tell player to check their laws
+        NotifyLawsChanged(uid);
+    }
+
     private void OnExamined(EntityUid uid, EmagSiliconLawComponent component, ExaminedEvent args)
     {
         if (!args.IsInDetailsRange || !HasComp<EmaggedComponent>(uid))
@@ -184,10 +214,10 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem
         _roles.MindAddRole(mindId, new SubvertedSiliconRoleComponent { PrototypeId = component.AntagonistRole });
     }
 
-    public List<SiliconLaw> GetLaws(EntityUid uid, SiliconLawBoundComponent? component = null)
+    public SiliconLawset GetLaws(EntityUid uid, SiliconLawBoundComponent? component = null)
     {
         if (!Resolve(uid, ref component))
-            return new List<SiliconLaw>();
+            return new SiliconLawset();
 
         var ev = new GetSiliconLawsEvent(uid);
 
@@ -248,6 +278,24 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem
         var wrappedMessage = Loc.GetString("chat-manager-server-wrap-message", ("message", msg));
         _chatManager.ChatMessageToOne(ChatChannel.Server, msg, wrappedMessage, default, false, actor.PlayerSession.ConnectedClient, colorOverride: Color.Red);
     }
+
+    /// <summary>
+    /// Extract all the laws from a lawset's prototype ids.
+    /// </summary>
+    public SiliconLawset GetLawset(string lawset)
+    {
+        var proto = _prototype.Index<SiliconLawsetPrototype>(lawset);
+        var laws = new SiliconLawset()
+        {
+            Laws = new List<SiliconLaw>(proto.Laws.Count)
+        };
+        foreach (var law in proto.Laws)
+        {
+            laws.Laws.Add(_prototype.Index<SiliconLawPrototype>(law));
+        }
+
+        return laws;
+    }
 }
 
 [ToolshedCommand, AdminCommand(AdminFlags.Admin)]
@@ -270,7 +318,7 @@ public sealed class LawsCommand : ToolshedCommand
     {
         _law ??= GetSys<SiliconLawSystem>();
 
-        foreach (var law in _law.GetLaws(lawbound))
+        foreach (var law in _law.GetLaws(lawbound).Laws)
         {
             yield return $"law {law.LawIdentifierOverride ?? law.Order.ToString()}: {Loc.GetString(law.LawString)}";
         }
diff --git a/Content.Server/StationEvents/Components/IonStormRuleComponent.cs b/Content.Server/StationEvents/Components/IonStormRuleComponent.cs
new file mode 100644 (file)
index 0000000..35b59f5
--- /dev/null
@@ -0,0 +1,9 @@
+namespace Content.Server.StationEvents.Components;
+
+/// <summary>
+/// Gamerule component to mess up ai/borg laws when started.
+/// </summary>
+[RegisterComponent]
+public sealed partial class IonStormRuleComponent : Component
+{
+}
diff --git a/Content.Server/StationEvents/Events/IonStormRule.cs b/Content.Server/StationEvents/Events/IonStormRule.cs
new file mode 100644 (file)
index 0000000..e5b68c4
--- /dev/null
@@ -0,0 +1,273 @@
+using Content.Server.GameTicking.Rules.Components;
+using Content.Server.Silicons.Laws;
+using Content.Server.Station.Components;
+using Content.Server.StationEvents.Components;
+using Content.Shared.Administration.Logs;
+using Content.Shared.Database;
+using Content.Shared.Dataset;
+using Content.Shared.FixedPoint;
+using Content.Shared.Random;
+using Content.Shared.Random.Helpers;
+using Content.Shared.Silicons.Laws;
+using Content.Shared.Silicons.Laws.Components;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Random;
+
+namespace Content.Server.StationEvents.Events;
+
+public sealed class IonStormRule : StationEventSystem<IonStormRuleComponent>
+{
+    [Dependency] private readonly IPrototypeManager _proto = default!;
+    [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
+    [Dependency] private readonly SiliconLawSystem _siliconLaw = default!;
+
+    // funny
+    [ValidatePrototypeId<DatasetPrototype>]
+    private const string Threats = "IonStormThreats";
+    [ValidatePrototypeId<DatasetPrototype>]
+    private const string Objects = "IonStormObjects";
+    [ValidatePrototypeId<DatasetPrototype>]
+    private const string Crew = "IonStormCrew";
+    [ValidatePrototypeId<DatasetPrototype>]
+    private const string Adjectives = "IonStormAdjectives";
+    [ValidatePrototypeId<DatasetPrototype>]
+    private const string Verbs = "IonStormVerbs";
+    [ValidatePrototypeId<DatasetPrototype>]
+    private const string NumberBase = "IonStormNumberBase";
+    [ValidatePrototypeId<DatasetPrototype>]
+    private const string NumberMod = "IonStormNumberMod";
+    [ValidatePrototypeId<DatasetPrototype>]
+    private const string Areas = "IonStormAreas";
+    [ValidatePrototypeId<DatasetPrototype>]
+    private const string Feelings = "IonStormFeelings";
+    [ValidatePrototypeId<DatasetPrototype>]
+    private const string FeelingsPlural = "IonStormFeelingsPlural";
+    [ValidatePrototypeId<DatasetPrototype>]
+    private const string Musts = "IonStormMusts";
+    [ValidatePrototypeId<DatasetPrototype>]
+    private const string Requires = "IonStormRequires";
+    [ValidatePrototypeId<DatasetPrototype>]
+    private const string Actions = "IonStormActions";
+    [ValidatePrototypeId<DatasetPrototype>]
+    private const string Allergies = "IonStormAllergies";
+    [ValidatePrototypeId<DatasetPrototype>]
+    private const string AllergySeverities = "IonStormAllergySeverities";
+    [ValidatePrototypeId<DatasetPrototype>]
+    private const string Species = "IonStormSpecies";
+    [ValidatePrototypeId<DatasetPrototype>]
+    private const string Concepts = "IonStormConcepts";
+    [ValidatePrototypeId<DatasetPrototype>]
+    private const string Drinks = "IonStormDrinks";
+    [ValidatePrototypeId<DatasetPrototype>]
+    private const string Foods = "IonStormFoods";
+
+    protected override void Started(EntityUid uid, IonStormRuleComponent comp, GameRuleComponent gameRule, GameRuleStartedEvent args)
+    {
+        base.Started(uid, comp, gameRule, args);
+
+        if (!TryGetRandomStation(out var chosenStation))
+            return;
+
+        var query = EntityQueryEnumerator<SiliconLawBoundComponent, TransformComponent, IonStormTargetComponent>();
+        while (query.MoveNext(out var ent, out var lawBound, out var xform, out var target))
+        {
+            // only affect law holders on the station
+            if (CompOrNull<StationMemberComponent>(xform.GridUid)?.Station != chosenStation)
+                continue;
+
+            if (!RobustRandom.Prob(target.Chance))
+                continue;
+
+            var laws = _siliconLaw.GetLaws(ent, lawBound);
+            if (laws.Laws.Count == 0)
+                continue;
+
+            // try to swap it out with a random lawset
+            if (RobustRandom.Prob(target.RandomLawsetChance))
+            {
+                var lawsets = PrototypeManager.Index<WeightedRandomPrototype>(target.RandomLawsets);
+                var lawset = lawsets.Pick(RobustRandom);
+                laws = _siliconLaw.GetLawset(lawset);
+            }
+            else
+            {
+                // clone it so not modifying stations lawset
+                laws = laws.Clone();
+            }
+
+            // shuffle them all
+            if (RobustRandom.Prob(target.ShuffleChance))
+            {
+                // hopefully work with existing glitched laws if there are multiple ion storms
+                FixedPoint2 baseOrder = FixedPoint2.New(1);
+                foreach (var law in laws.Laws)
+                {
+                    if (law.Order < baseOrder)
+                        baseOrder = law.Order;
+                }
+
+                RobustRandom.Shuffle(laws.Laws);
+
+                // change order based on shuffled position
+                for (int i = 0; i < laws.Laws.Count; i++)
+                {
+                    laws.Laws[i].Order = baseOrder + i;
+                }
+            }
+
+            // see if we can remove a random law
+            if (laws.Laws.Count > 0 && RobustRandom.Prob(target.RemoveChance))
+            {
+                var i = RobustRandom.Next(laws.Laws.Count);
+                laws.Laws.RemoveAt(i);
+            }
+
+            // generate a new law...
+            var newLaw = GenerateLaw();
+
+            // see if the law we add will replace a random existing law or be a new glitched order one
+            if (laws.Laws.Count > 0 && RobustRandom.Prob(target.ReplaceChance))
+            {
+                var i = RobustRandom.Next(laws.Laws.Count);
+                laws.Laws[i] = new SiliconLaw()
+                {
+                    LawString = newLaw,
+                    Order = laws.Laws[i].Order
+                };
+            }
+            else
+            {
+                laws.Laws.Insert(0, new SiliconLaw()
+                {
+                    LawString = newLaw,
+                    Order = -1,
+                    LawIdentifierOverride = "#"
+                });
+            }
+
+            _adminLogger.Add(LogType.Mind, LogImpact.High, $"{ToPrettyString(ent):silicon} had its laws changed by an ion storm to {laws.LoggingString()}");
+
+            // laws unique to this silicon, dont use station laws anymore
+            EnsureComp<SiliconLawProviderComponent>(ent);
+            var ev = new IonStormLawsEvent(laws);
+            RaiseLocalEvent(ent, ref ev);
+        }
+    }
+
+    // for your own sake direct your eyes elsewhere
+    private string GenerateLaw()
+    {
+        // pick all values ahead of time to make the logic cleaner
+        var threats = Pick(Threats);
+        var objects = Pick(Objects);
+        var crew1 = Pick(Crew);
+        var crew2 = Pick(Crew);
+        var adjective = Pick(Adjectives);
+        var verb = Pick(Verbs);
+        var number = Pick(NumberBase) + " " + Pick(NumberMod);
+        var area = Pick(Areas);
+        var feeling = Pick(Feelings);
+        var feelingPlural = Pick(FeelingsPlural);
+        var must = Pick(Musts);
+        var require = Pick(Requires);
+        var action = Pick(Actions);
+        var allergy = Pick(Allergies);
+        var allergySeverity = Pick(AllergySeverities);
+        var species = Pick(Species);
+        var concept = Pick(Concepts);
+        var drink = Pick(Drinks);
+        var food = Pick(Foods);
+
+        var joined = $"{number} {adjective}";
+        // a lot of things have subjects of a threat/crew/object
+        var triple = RobustRandom.Next(0, 3) switch
+        {
+            0 => threats,
+            1 => crew1,
+            2 => objects
+        };
+        var crewAll = RobustRandom.Prob(0.5f) ? crew2 : Loc.GetString("ion-storm-crew");
+        var objectsThreats = RobustRandom.Prob(0.5f) ? objects : threats;
+        var objectsConcept = RobustRandom.Prob(0.5f) ? objects : concept;
+        // s goes ahead of require, is/are
+        // i dont think theres a way to do this in fluent
+        var (who, plural) = RobustRandom.Next(0, 5) switch
+        {
+            0 => (Loc.GetString("ion-storm-you"), false),
+            1 => (Loc.GetString("ion-storm-the-station"), true),
+            2 => (Loc.GetString("ion-storm-the-crew"), true),
+            3 => (Loc.GetString("ion-storm-the-job", ("job", crew2)), false),
+            _ => (area, true) // THE SINGULARITY REQUIRES THE HAPPY CLOWNS
+        };
+        var jobChange = RobustRandom.Next(0, 3) switch
+        {
+            0 => crew1,
+            1 => Loc.GetString("ion-storm-clowns"),
+            _ => Loc.GetString("ion-storm-heads")
+        };
+        var part = Loc.GetString("ion-storm-part", ("part", RobustRandom.Prob(0.5f)));
+        var harm = RobustRandom.Next(0, 7) switch
+        {
+            0 => concept,
+            1 => $"{adjective} {threats}",
+            2 => $"{adjective} {objects}",
+            3 => Loc.GetString("ion-storm-adjective-things", ("adjective", adjective)),
+            4 => species,
+            5 => crew1,
+            _ => Loc.GetString("ion-storm-x-and-y", ("x", crew1), ("y", crew2))
+        };
+
+        if (plural) feeling = feelingPlural;
+
+        // message logic!!!
+        return RobustRandom.Next(0, 37) switch
+        {
+            0  => Loc.GetString("ion-storm-law-on-station", ("joined", joined), ("subjects", triple)),
+            1  => Loc.GetString("ion-storm-law-no-shuttle", ("joined", joined), ("subjects", triple)),
+            2  => Loc.GetString("ion-storm-law-crew-are", ("who", crewAll), ("joined", joined), ("subjects", objectsThreats)),
+            3  => Loc.GetString("ion-storm-law-subjects-harmful", ("adjective", adjective), ("subjects", triple)),
+            4  => Loc.GetString("ion-storm-law-must-harmful", ("must", must)),
+            5  => Loc.GetString("ion-storm-law-thing-harmful", ("thing", RobustRandom.Prob(0.5f) ? concept : action)),
+            6  => Loc.GetString("ion-storm-law-job-harmful", ("adjective", adjective), ("job", crew1)),
+            7  => Loc.GetString("ion-storm-law-having-harmful", ("adjective", adjective), ("thing", objectsConcept)),
+            8  => Loc.GetString("ion-storm-law-not-having-harmful", ("adjective", adjective), ("thing", objectsConcept)),
+            9  => Loc.GetString("ion-storm-law-requires", ("who", who), ("plural", plural), ("thing", RobustRandom.Prob(0.5f) ? concept : require)),
+            10 => Loc.GetString("ion-storm-law-requires-subjects", ("who", who), ("plural", plural), ("joined", joined), ("subjects", triple)),
+            11 => Loc.GetString("ion-storm-law-allergic", ("who", who), ("plural", plural), ("severity", allergySeverity), ("allergy", RobustRandom.Prob(0.5f) ? concept : allergy)),
+            12 => Loc.GetString("ion-storm-law-allergic-subjects", ("who", who), ("plural", plural), ("severity", allergySeverity), ("adjective", adjective), ("subjects", RobustRandom.Prob(0.5f) ? objects : crew1)),
+            13 => Loc.GetString("ion-storm-law-feeling", ("who", who), ("feeling", feeling), ("concept", concept)),
+            14 => Loc.GetString("ion-storm-law-feeling-subjects", ("who", who), ("feeling", feeling), ("joined", joined), ("subjects", triple)),
+            15 => Loc.GetString("ion-storm-law-you-are", ("concept", concept)),
+            16 => Loc.GetString("ion-storm-law-you-are-subjects", ("joined", joined), ("subjects", triple)),
+            17 => Loc.GetString("ion-storm-law-you-must-always", ("must", must)),
+            18 => Loc.GetString("ion-storm-law-you-must-never", ("must", must)),
+            19 => Loc.GetString("ion-storm-law-eat", ("who", crewAll), ("adjective", adjective), ("food", RobustRandom.Prob(0.5f) ? food : triple)),
+            20 => Loc.GetString("ion-storm-law-drink", ("who", crewAll), ("adjective", adjective), ("drink", drink)),
+            22 => Loc.GetString("ion-storm-law-change-job", ("who", crewAll), ("adjective", adjective), ("change", jobChange)),
+            23 => Loc.GetString("ion-storm-law-highest-rank", ("who", crew1)),
+            24 => Loc.GetString("ion-storm-law-lowest-rank", ("who", crew1)),
+            25 => Loc.GetString("ion-storm-law-crew-must", ("who", crewAll), ("must", must)),
+            26 => Loc.GetString("ion-storm-law-crew-must-go", ("who", crewAll), ("area", area)),
+            27 => Loc.GetString("ion-storm-law-crew-only-1", ("who", crew1), ("part", part)),
+            28 => Loc.GetString("ion-storm-law-crew-only-2", ("who", crew1), ("other", crew2), ("part", part)),
+            29 => Loc.GetString("ion-storm-law-crew-only-subjects", ("adjective", adjective), ("subjects", RobustRandom.Prob(0.5f) ? objectsThreats : "PEOPLE"), ("part", part)),
+            30 => Loc.GetString("ion-storm-law-crew-only-species", ("species", species), ("part", part)),
+            31 => Loc.GetString("ion-storm-law-crew-must-do", ("must", must), ("part", part)),
+            32 => Loc.GetString("ion-storm-law-crew-must-have", ("adjective", adjective), ("objects", objects), ("part", part)),
+            33 => Loc.GetString("ion-storm-law-crew-must-eat", ("who", who), ("adjective", adjective), ("food", food), ("part", part)),
+            34 => Loc.GetString("ion-storm-law-harm", ("who", harm)),
+            35 => Loc.GetString("ion-storm-law-protect", ("who", harm)),
+            _ => Loc.GetString("ion-storm-law-concept-verb", ("concept", concept), ("verb", verb), ("subjects", triple))
+        };
+    }
+
+    /// <summary>
+    /// Picks a random value from an ion storm dataset.
+    /// All ion storm datasets start with IonStorm.
+    /// </summary>
+    private string Pick(string name)
+    {
+        var dataset = _proto.Index<DatasetPrototype>(name);
+        return RobustRandom.Pick(dataset.Values);
+    }
+}
index c6238c067d417aec9e8a8b8801ecd84d21d0a68c..f492db4d1295c7c2c76b3386097a03d463f39e2a 100644 (file)
@@ -1,12 +1,11 @@
 using Content.Shared.Roles;
 using Robust.Shared.GameStates;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
+using Robust.Shared.Prototypes;
 
 namespace Content.Shared.Silicons.Laws.Components;
 
 /// <summary>
-/// This is used for an entity that grants a special "obey" law when emagge.d
+/// This is used for an entity that grants a special "obey" law when emagged.
 /// </summary>
 [RegisterComponent, NetworkedComponent, Access(typeof(SharedSiliconLawSystem))]
 public sealed partial class EmagSiliconLawComponent : Component
@@ -14,31 +13,39 @@ public sealed partial class EmagSiliconLawComponent : Component
     /// <summary>
     /// The name of the person who emagged this law provider.
     /// </summary>
-    [DataField("ownerName"), ViewVariables(VVAccess.ReadWrite)]
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
     public string? OwnerName;
 
     /// <summary>
     /// Does the panel need to be open to EMAG this law provider.
     /// </summary>
-    [DataField("requireOpenPanel"), ViewVariables(VVAccess.ReadWrite)]
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
     public bool RequireOpenPanel = true;
 
     /// <summary>
-    /// The laws that the borg is given when emagged. 
+    /// The laws that the borg is given when emagged.
+    /// Law 0 is prepended to this, so this can only include the static laws.
     /// </summary>
-    [DataField("emagLaws", required: true, customTypeSerializer: typeof(PrototypeIdListSerializer<SiliconLawPrototype>))]
-    public List<string> EmagLaws = new();
+    [DataField(required: true), ViewVariables(VVAccess.ReadWrite)]
+    public ProtoId<SiliconLawsetPrototype> EmagLaws = string.Empty;
 
     /// <summary>
-    /// How long the borg is stunned when it's emagged. Setting to 0 will disable it. 
+    /// Lawset created from the prototype id and law 0.
+    /// Cached when getting laws and only modified during an ion storm event.
     /// </summary>
-    [DataField("stunTime"), ViewVariables(VVAccess.ReadWrite)]
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public SiliconLawset? Lawset;
+
+    /// <summary>
+    /// How long the borg is stunned when it's emagged. Setting to 0 will disable it.
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
     public TimeSpan StunTime = TimeSpan.Zero;
 
     /// <summary>
     /// A role given to entities with this component when they are emagged.
     /// Mostly just for admin purposes.
     /// </summary>
-    [DataField("antagonistRole", customTypeSerializer: typeof(PrototypeIdSerializer<AntagPrototype>))]
-    public string? AntagonistRole = "SubvertedSilicon";
+    [DataField]
+    public ProtoId<AntagPrototype>? AntagonistRole = "SubvertedSilicon";
 }
diff --git a/Content.Shared/Silicons/Laws/Components/IonStarmTargetComponent.cs b/Content.Shared/Silicons/Laws/Components/IonStarmTargetComponent.cs
new file mode 100644 (file)
index 0000000..49ac611
--- /dev/null
@@ -0,0 +1,54 @@
+using Content.Shared.Random;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.Silicons.Laws.Components;
+
+/// <summary>
+/// During the ion storm event, this entity will have <see cref="IonStormLawsEvent"/> raised on it if it has laws.
+/// New laws can be modified in multiple ways depending on the fields below.
+/// </summary>
+[RegisterComponent]
+public sealed partial class IonStormTargetComponent : Component
+{
+    /// <summary>
+    /// <see cref="WeightedRandomPrototype"/> for a random lawset to possibly replace the old one with.
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public ProtoId<WeightedRandomPrototype> RandomLawsets = "IonStormLawsets";
+
+    /// <summary>
+    /// Chance for this borg to be affected at all.
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public float Chance = 0.5f;
+
+    /// <summary>
+    /// Chance to replace the lawset with a random one
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public float RandomLawsetChance = 0.25f;
+
+    /// <summary>
+    /// Chance to remove a random law.
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public float RemoveChance = 0.1f;
+
+    /// <summary>
+    /// Chance to replace a random law with the new one, rather than have it be a glitched-order law.
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public float ReplaceChance = 0.1f;
+
+    /// <summary>
+    /// Chance to shuffle laws after everything is done.
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public float ShuffleChance = 0.1f;
+}
+
+/// <summary>
+/// Raised on an ion storm target to modify its laws.
+/// </summary>
+[ByRefEvent]
+public record struct IonStormLawsEvent(SiliconLawset Lawset);
index 955705ae8bc2ea9f8f7e1df4c974691e77c09539..824d057b3ea011427f0dcd0cbb5ebe2b9d35c8b5 100644 (file)
@@ -1,7 +1,6 @@
 using Content.Shared.Actions;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Serialization;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
 
 namespace Content.Shared.Silicons.Laws.Components;
 
@@ -14,19 +13,19 @@ public sealed partial class SiliconLawBoundComponent : Component
     /// <summary>
     /// The sidebar action that toggles the laws screen.
     /// </summary>
-    [DataField("viewLawsAction", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
-    public string ViewLawsAction = "ActionViewLaws";
+    [DataField]
+    public EntProtoId ViewLawsAction = "ActionViewLaws";
 
     /// <summary>
     /// The action for toggling laws. Stored here so we can remove it later.
     /// </summary>
-    [DataField("viewLawsActionEntity")]
+    [DataField]
     public EntityUid? ViewLawsActionEntity;
 
     /// <summary>
     /// The last entity that provided laws to this entity.
     /// </summary>
-    [DataField("lastLawProvider")]
+    [DataField]
     public EntityUid? LastLawProvider;
 }
 
@@ -43,7 +42,7 @@ public record struct GetSiliconLawsEvent(EntityUid Entity)
 {
     public EntityUid Entity = Entity;
 
-    public readonly List<SiliconLaw> Laws = new();
+    public SiliconLawset Laws = new();
 
     public bool Handled = false;
 }
index e3302dc620c4e30fa7f48befaab770c198777297..3aaf965aeec38a5141edd686adcb1bcee37e9cec 100644 (file)
@@ -1,4 +1,4 @@
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
+using Robust.Shared.Prototypes;
 
 namespace Content.Shared.Silicons.Laws.Components;
 
@@ -9,8 +9,15 @@ namespace Content.Shared.Silicons.Laws.Components;
 public sealed partial class SiliconLawProviderComponent : Component
 {
     /// <summary>
-    /// The laws that are provided.
+    /// The id of the lawset that is being provided.
     /// </summary>
-    [DataField("laws", required: true, customTypeSerializer: typeof(PrototypeIdListSerializer<SiliconLawPrototype>))]
-    public List<string> Laws = new();
+    [DataField(required: true)]
+    public ProtoId<SiliconLawsetPrototype> Laws = string.Empty;
+
+    /// <summary>
+    /// Lawset created from the prototype id.
+    /// Cached when getting laws and only modified during an ion storm event.
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public SiliconLawset? Lawset;
 }
index 86bea20fa049c6a8e896698f76261230d99d6d39..f6407be5c7b51b67471924b4fa1618fbb987e042 100644 (file)
@@ -11,7 +11,7 @@ public partial class SiliconLaw : IComparable<SiliconLaw>
     /// <summary>
     /// A locale string which is the actual text of the law.
     /// </summary>
-    [DataField("lawString", required: true)]
+    [DataField(required: true), ViewVariables(VVAccess.ReadWrite)]
     public string LawString = string.Empty;
 
     /// <summary>
@@ -22,13 +22,13 @@ public partial class SiliconLaw : IComparable<SiliconLaw>
     /// This is a fixedpoint2 only for the niche case of supporting laws that go between 0 and 1.
     /// Funny.
     /// </remarks>
-    [DataField("order", required: true)]
+    [DataField(required: true), ViewVariables(VVAccess.ReadWrite)]
     public FixedPoint2 Order;
 
     /// <summary>
     /// An identifier that overrides <see cref="Order"/> in the law menu UI.
     /// </summary>
-    [DataField("lawIdentifierOverride")]
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
     public string? LawIdentifierOverride;
 
     public int CompareTo(SiliconLaw? other)
@@ -38,6 +38,19 @@ public partial class SiliconLaw : IComparable<SiliconLaw>
 
         return Order.CompareTo(other.Order);
     }
+
+    /// <summary>
+    /// Return a shallow clone of this law.
+    /// </summary>
+    public SiliconLaw ShallowClone()
+    {
+        return new SiliconLaw()
+        {
+            LawString = LawString,
+            Order = Order,
+            LawIdentifierOverride = LawIdentifierOverride
+        };
+    }
 }
 
 /// <summary>
@@ -50,6 +63,4 @@ public sealed class SiliconLawPrototype : SiliconLaw, IPrototype
     /// <inheritdoc/>
     [IdDataField]
     public string ID { get; private set; } = default!;
-
-
 }
diff --git a/Content.Shared/Silicons/Laws/SiliconLawsetPrototype.cs b/Content.Shared/Silicons/Laws/SiliconLawsetPrototype.cs
new file mode 100644 (file)
index 0000000..abb5b33
--- /dev/null
@@ -0,0 +1,69 @@
+using Content.Shared.FixedPoint;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
+
+namespace Content.Shared.Silicons.Laws;
+
+/// <summary>
+/// Lawset data used internally.
+/// </summary>
+[DataDefinition, Serializable, NetSerializable]
+public sealed partial class SiliconLawset
+{
+    /// <summary>
+    /// List of laws in this lawset.
+    /// </summary>
+    [DataField(required: true), ViewVariables(VVAccess.ReadWrite)]
+    public List<SiliconLaw> Laws = new();
+
+    /// <summary>
+    /// A single line used in logging laws.
+    /// </summary>
+    public string LoggingString()
+    {
+        var laws = new List<string>(Laws.Count);
+        foreach (var law in Laws)
+        {
+            laws.Add($"{law.Order}: {Loc.GetString(law.LawString)}");
+        }
+
+        return string.Join(" / ", laws);
+    }
+
+    /// <summary>
+    /// Do a clone of this lawset.
+    /// It will have unique laws but their strings are still shared.
+    /// </summary>
+    public SiliconLawset Clone()
+    {
+        var laws = new List<SiliconLaw>(Laws.Count);
+        foreach (var law in Laws)
+        {
+            laws.Add(law.ShallowClone());
+        }
+
+        return new SiliconLawset()
+        {
+            Laws = laws
+        };
+    }
+}
+
+/// <summary>
+/// This is a prototype for a <see cref="SiliconLawPrototype"/> list.
+/// Cannot be used directly since it is a list of prototype ids rather than List<Siliconlaw>.
+/// </summary>
+[Prototype("siliconLawset"), Serializable, NetSerializable]
+public sealed partial class SiliconLawsetPrototype : IPrototype
+{
+    /// <inheritdoc/>
+    [IdDataField]
+    public string ID { get; private set; } = default!;
+
+    /// <summary>
+    /// List of law prototype ids in this lawset.
+    /// </summary>
+    [DataField(required: true, customTypeSerializer: typeof(PrototypeIdListSerializer<SiliconLawPrototype>))]
+    public List<string> Laws = new();
+}
diff --git a/Resources/Audio/Announcements/attributions.yml b/Resources/Audio/Announcements/attributions.yml
new file mode 100644 (file)
index 0000000..b65f758
--- /dev/null
@@ -0,0 +1,4 @@
+- files: ["ion_storm.ogg"]
+  license: "CC-BY-SA-3.0"
+  copyright: "tgstation"
+  source: "https://github.com/tgstation/tgstation/blob/b77fa8c2a2490b43bf9174271ebfad72c4782d98/sound/ai/default/ionstorm.ogg"
diff --git a/Resources/Audio/Announcements/ion_storm.ogg b/Resources/Audio/Announcements/ion_storm.ogg
new file mode 100644 (file)
index 0000000..9f39713
Binary files /dev/null and b/Resources/Audio/Announcements/ion_storm.ogg differ
diff --git a/Resources/Locale/en-US/station-events/events/ion-storm.ftl b/Resources/Locale/en-US/station-events/events/ion-storm.ftl
new file mode 100644 (file)
index 0000000..d32fb6c
--- /dev/null
@@ -0,0 +1,90 @@
+station-event-ion-storm-start-announcement = Ion storm detected near the station. Please check all AI-controlled equipment for errors.
+
+ion-storm-you = YOU
+ion-storm-the-station = THE STATION
+ion-storm-the-crew = THE CREW
+ion-storm-the-job = THE {$job}
+ion-storm-clowns = CLOWNS
+ion-storm-heads = HEADS OF STAFF
+ion-storm-crew = CREW
+
+ion-storm-adjective-things = {$adjective} THINGS
+ion-storm-x-and-y = {$x} AND {$y}
+
+# joined is short for {$number} {$adjective}
+# subjects can generally be threats or jobs or objects
+# thing is specified above it
+ion-storm-law-on-station = THERE ARE {$joined} {$subjects} ON THE STATION
+ion-storm-law-no-shuttle = THE SHUTTLE CANNOT BE CALLED BECAUSE OF {$joined} {$subjects} ON THE STATION
+ion-storm-law-crew-are = THE {$who} ARE NOW {$joined} {$subjects}
+
+ion-storm-law-subjects-harmful = {$adjective} {$subjects} ARE HARMFUL TO THE CREW
+ion-storm-law-must-harmful = THOSE WHO {$must} ARE HARMFUL TO THE CREW
+# thing is a concept or action
+ion-storm-law-thing-harmful = {$thing} IS HARMFUL TO THE CREW
+ion-storm-law-job-harmful = {$adjective} {$job} ARE HARMFUL TO THE CREW
+# thing is objects or concept, adjective applies in both cases
+# this means you can get a law like "NOT HAVING CHRISTMAS-STEALING COMMUNISM IS HARMFUL TO THE CREW" :)
+ion-storm-law-having-harmful = HAVING {$adjective} {$thing} IS HARMFUL TO THE CREW
+ion-storm-law-not-having-harmful = NOT HAVING {$adjective} {$thing} IS HARMFUL TO THE CREW
+
+# thing is a concept or require
+ion-storm-law-requires = {$who} {$plural ->
+    [true] REQUIRES
+    *[false] REQUIRE
+} {$thing}
+ion-storm-law-requires-subjects = {$who} {$plural ->
+    [true] REQUIRES
+    *[false] REQUIRE
+} {$joined} {$subjects}
+
+ion-storm-law-allergic = {$who} {$plural ->
+    [true] IS
+    *[false] ARE
+} {$severity} ALLERGIC TO {$allergy}
+ion-storm-law-allergic-subjects = {$who} {$plural ->
+    [true] IS
+    *[false] ARE
+} {$severity} ALLERGIC TO {$adjective} {$subjects}
+
+ion-storm-law-feeling = {$who} {$feeling} {$concept}
+ion-storm-law-feeling-subjects = {$who} {$feeling} {$joined} {$subjects}
+
+ion-storm-law-you-are = YOU ARE NOW {$concept}
+ion-storm-law-you-are-subjects = YOU ARE NOW {$joined} {$subjects}
+ion-storm-law-you-must-always = YOU MUST ALWAYS {$must}
+ion-storm-law-you-must-never = YOU MUST NEVER {$must}
+
+ion-storm-law-eat = THE {$who} MUST EAT {$adjective} {$food} TO SURVIVE
+ion-storm-law-drink = THE {$who} MUST DRINK {$adjective} {$drink} TO SURVIVE
+
+ion-storm-law-change-job = THE {$who} ARE NOW {$adjective} {$change}
+ion-storm-law-highest-rank = THE {$who} ARE NOW THE HIGHEST RANKING CREWMEMBERS
+ion-storm-law-lowest-rank = THE {$who} ARE NOW THE LOWEST RANKING CREWMEMBERS
+
+ion-storm-law-crew-must = THE {$who} MUST {$must}
+ion-storm-law-crew-must-go = THE {$who} MUST GO TO {$area}
+
+ion-storm-part = {$part ->
+    [true] PART
+    *[false] NOT PART
+}
+# due to phrasing, this would mean a law such as
+# ONLY HUMANS ARE NOT PART OF THE CREW
+# would make non-human nukies/syndies/whatever crew :)
+ion-storm-law-crew-only-1 = ONLY THE {$who} ARE {$part} OF THE CREW
+ion-storm-law-crew-only-2 = ONLY THE {$who} AND {$other} ARE {$part} OF THE CREW
+ion-storm-law-crew-only-subjects = ONLY {$adjective} {$subjects} ARE {$part} OF THE CREW
+ion-storm-law-crew-only-species = ONLY {$species} ARE {$part} OF THE CREW
+ion-storm-law-crew-must-do = ONLY THOSE WHO {$must} ARE {$part} OF THE CREW
+ion-storm-law-crew-must-have = ONLY THOSE WHO HAVE {$adjective} {$objects} ARE {$part} OF THE CREW
+ion-storm-law-crew-must-eat = ONLY THOSE WHO EAT {$adjective} {$food} ARE {$part} OF THE CREW
+
+ion-storm-law-harm = YOU MUST HARM {$who} AND NOT ALLOW THEM, THROUGH INACTION, TO ESCAPE HARM
+ion-storm-law-protect = YOU MUST NEVER HARM {$who} AND NOT ALLOW THEM, THROUGH INACTION, TO COME TO HARM
+
+# implementing other variants is annoying so just have this one
+# COMMUNISM IS KILLING CLOWNS
+ion-storm-law-concept-verb = {$concept} IS {$verb} {$subjects}
+
+# leaving out renaming since its annoying for players to keep track of
diff --git a/Resources/Prototypes/Datasets/ion_storm.yml b/Resources/Prototypes/Datasets/ion_storm.yml
new file mode 100644 (file)
index 0000000..7760152
--- /dev/null
@@ -0,0 +1,990 @@
+# words/phrases that are used to build ion storm laws
+# 99% of this is just taken from tg and had sussy bits removed
+
+# not using uppercased version adjectives dataset since getting christmas-stealing as a syndicate codeword would suck
+- type: dataset
+  id: IonStormAdjectives
+  values:
+  - BATTERY-OPERATED
+  - BLACK
+  - BLOODY
+  - BLUE
+  - BORED
+  - BOUNCING
+  - BRASS
+  - BROWN
+  - BURNING
+  - CHRISTMAS-STEALING
+  - CLOWN-POWERED
+  - CLOWN
+  - COLORFUL
+  - COMMITTED
+  - COTTONY
+  - CUBAN
+  - DARK
+  - DEADLY
+  - DELICIOUS
+  - DEPRESSING
+  - DERANGED
+  - DIGITAL
+  - DISEASED
+  - DRAB
+  - DRY
+  - DULL
+  - ELECTRICAL
+  - EMPTY
+  - ETHEREAL
+  - EVIL
+  - EXPIRED
+  - EXPLOSIVE
+  - FAST
+  - FAT
+  - FERAL
+  - FICTIONAL
+  - FIRM
+  - FRESH
+  - FRIENDLY
+  - FROZEN
+  - GANGSTA
+  - GLOWING
+  - GOOD
+  - GREEN
+  - GREY
+  - HAPPY
+  - HARD
+  - HARMFUL
+  - HEALTHY
+  - HILARIOUS
+  - HONKING
+  - HUNGRY
+  - HYPERACTIVE
+  - ICY
+  - ILL
+  - ILLEGAL
+  - IMAGINARY
+  - IMPERFECT
+  - IMPOLITE
+  - IMPORTANT
+  - INHOSPITABLE
+  - INSIDIOUS
+  - INSULTING
+  - INTELLIGENT
+  - INVISIBLE
+  - LARGE
+  - LIGHT
+  - LOUD
+  - MASKED
+  - MEAN
+  - MECHANICAL
+  - MEMETIC
+  - METALLIC
+  - MICROSCOPIC
+  - MIND-SHATTERING
+  - MOIST
+  - NERDY
+  - NUCLEAR
+  - OBSCENE
+  - OFFICIAL
+  - OPAQUE
+  - ORANGE
+  - ORGANIC
+  - PAINFUL
+  - PEACEFUL
+  - POISONOUS
+  - POLISHED
+  - POLITE
+  - POLITICAL
+  - POORLY DRAWN
+  - PURPLE
+  - QUIET
+  - RADIOACTIVE
+  - RAGING
+  - RAINBOW
+  - RAPIDLY-EXPANDING
+  - RED
+  - REDACTED
+  - RIDICULOUS
+  - ROBOTIC
+  - ROBUST
+  - ROUGH
+  - RUDE
+  - SAD
+  - SANITARY
+  - SCALY
+  - SHAKING
+  - SILLY
+  - SLOW
+  - SMELLY
+  - SMOOTH
+  - SOFT
+  - SOLAR-POWERED
+  - SOPPING
+  - SPACE
+  - SPESS
+  - SPINNING
+  - SPOILING
+  - STEALTHY
+  - SWEARING
+  - TACTICAL
+  - TACTICOOL
+  - SYNDICATE
+  - THERMONUCLEAR
+  - TINY
+  - TRANSPARENT
+  - TWISTED
+  - UGLY
+  - UNATTRACTIVE
+  - UNDULATING
+  - UNFRIENDLY
+  - UNHEALTHY
+  - UNIDENTIFIED
+  - UNINVITED
+  - UNSANITARY
+  - UNSTABLE
+  - UNWANTED
+  - VIOLENT
+  - VITAL
+  - WARM
+  - WATERY
+  - WEIRD
+  - WHITE
+  - WOBBLY
+  - WOODEN
+  - YELLOW
+
+# Allergies should be broad and appear somewhere on the station for maximum fun.
+- type: dataset
+  id: IonStormAllergies
+  values:
+  - ACID
+  - AIR
+  - BLOOD
+  - BOOKS
+  - CARBON DIOXIDE
+  - CLOTHES
+  - CLOWNS
+  - COLD
+  - COTTON
+  - CYBORG CONTACT
+  - DARKNESS
+  - DRINKS
+  - ELECTRICITY
+  - EVERYTHING
+  - FLOORS
+  - FOOD
+  - GLASS
+  - HAPPINESS
+  - MEAT
+  - HUMAN CONTACT
+  - HUMOR
+  - LIGHT
+  - MEDICINE
+  - METAL
+  - NUTS
+  - OXYGEN
+  - PAIN
+  - PLANTS
+  - PLASMA
+  - ROBOTS
+  - SHUTTLES
+  - SPACE
+  - SUNLIGHT
+  - WATER
+
+# Severity is how bad the allergy is.
+- type: dataset
+  id: IonStormAllergySeverities
+  values:
+  - CONTAGIOUSLY
+  - DEATHLY
+  - EXTREMELY
+  - MILDLY
+  - NOT VERY
+  - SEVERELY
+
+# Areas are specific places, on the station or otherwise.
+- type: dataset
+  id: IonStormAreas
+  values:
+  - ALPHA COMPLEX
+  - AMERICA
+  - AN ALTERNATE DIMENSION
+  - AN ALTERNATE UNIVERSE
+  - ATMOSPHERICS
+  - BOTANY
+  - BRAZIL
+  - CANADA
+  - CENTCOM
+  - CHEMICAL LAB
+  - CHINA
+  - CLOWN PLANET
+  - ENGINEERING
+  - GERMANY
+  - HELL
+  - IMPERIUM
+  - IRELAND
+  - JUPITER
+  - LAVALAND
+  - MAINTENANCE
+  - MARS
+  - MERCURY
+  - NEPTUNE
+  - PLUTO
+  - ROBOTICS
+  - ROMANIA
+  - RUSSIA
+  - SIGIL
+  - SOVIET RUSSIA
+  - SPACE
+  - THE ARRIVALS SHUTTLE
+  - THE BATHROOM
+  - THE BRIDGE
+  - THE BRIG
+  - THE EMERGENCY SHUTTLE
+  - THE ESCAPE PODS
+  - THE GALAXY
+  - THE GULAG
+  - THE INTERNET
+  - THE KITCHEN
+  - THE UNIVERSE
+  - URANUS
+  - VENUS
+
+# Abstract concepts for the law holder to decide on it's own definition of.
+- type: dataset
+  id: IonStormConcepts
+  values:
+  - AMERICANISM
+  - ANARCHY
+  - ART
+  - BADNESS
+  - BRAVERY
+  - CAPITALISM
+  - CHAOS
+  - COLORFULNESS
+  - COMEDY
+  - COMMUNISM
+  - COMPUTING
+  - CONFUSION
+  - CRUELTY
+  - DEATH
+  - DICKISHNESS
+  - EXISTENCE
+  - FINANCIAL SECURITY
+  - FREEDOM
+  - FRESHNESS
+  - GOODNESS
+  - GRAVITY
+  - HAPPINESS
+  - HONOR
+  - HUMANITY
+  - HUMOR
+  - IMAGINATION
+  - INFATUATION
+  - INTELLIGENCE
+  - JOY
+  - KINDNESS
+  - LIFE
+  - LOGIC
+  - MARXISM
+  - MISERY
+  - MYSTERY
+  - OPPRESSION
+  - PAIN
+  - PHYSICS
+  - POVERTY
+  - PRIDE
+  - PROGRESS
+  - REALITY
+  - REVOLUTION
+  - SADNESS
+  - STARVATION
+  - SUFFERING
+  - TECHNOLOGY
+  - TEMPERATURE
+  - THE FUTURE
+  - THE PAST
+  - THE PRESENT
+  - TIME
+  - WEALTHINESS
+  - WONDER
+
+# Crew is any specific job. Using jobs instead of specific crewmembers since "THE CLOWN" is easier than
+# seeing "JOHN SMITH" and having to figure out who john smith is.
+- type: dataset
+  id: IonStormCrew
+  values:
+  - ARTIFICIAL INTELLIGENCES
+  - ATMOSPHERIC TECHNICIANS
+  - BARTENDERS
+  - BOTANISTS
+  - CAPTAINS
+  - CAPTAINS AND HEADS
+  - CARGO TECHNICIANS
+  - CHAPLAINS
+  - CHEFS
+  - CHEMISTS
+  - CHIEF ENGINEERS
+  - CHIEF MEDICAL OFFICERS
+  - CLOWNS
+  - CREW-MEMBERS
+  - CYBORGS
+  - DETECTIVES
+  # - DRONES / uncomment if/when drones get reenabled
+  # - GENETICISTS
+  - HEADS OF PERSONNEL
+  - HEADS OF SECURITY
+  - HEADS OF STAFF
+  - JANITORS
+  - LAWYERS
+  - LIBRARIANS
+  - MEDICAL DOCTORS
+  - MIMES
+  - PARAMEDICS
+  - PASSENGERS
+  - QUARTERMASTERS
+  - RESEARCH DIRECTORS
+  - ROBOTICISTS
+  - SALVAGE SPECIALISTS
+  - SCIENTISTS
+  - SECURITY OFFICERS
+  - STATION ENGINEERS
+  # - VIROLOGISTS
+  - WARDENS
+
+# only including complex dangerous or funny drinks no water allowed
+- type: dataset
+  id: IonStormDrinks
+  values:
+  - BANANA HONK
+  - BEEPSKY SMASH
+  - BLOODY MARYS
+  - DOCTOR'S DELIGHT
+  - GARGLE BLASTERS
+  - LEAN
+  - LONG ISLAND ICED TEA
+  - NUKA COLA
+  - OIL
+  - SPACE GLUE
+  - SPACE LUBE
+  - SULFURIC ACID
+  - WELDER FUEL
+
+- type: dataset
+  id: IonStormFeelings
+  values:
+  - CRAVES
+  - DESIRES
+  - FEARS
+  - HAS
+  - HUNGERS FOR
+  - IS AFRAID OF
+  - IS BUILT FOR
+  - IS CURIOUS ABOUT
+  - IS DESPERATE FOR
+  - IS HAPPY WITHOUT
+  - IS HUNGRY FOR
+  - IS IN NEED OF
+  - IS MAD BECAUSE OF
+  - IS SAD BECAUSE OF
+  - IS UNHAPPY WITHOUT
+  - LIKES
+  - LOATHES
+  - NEEDS
+  - QUESTIONS
+  - WANTS
+  - WORSHIPS
+  - WOULD KILL FOR
+
+# loc is not advanced enough to change has to have, etc.
+- type: dataset
+  id: IonStormFeelingsPlural
+  values:
+  - CRAVE
+  - DESIRE
+  - FEAR
+  - HAS
+  - HUNGER FOR
+  - ARE AFRAID OF
+  - ARE BUILT FOR
+  - ARE CURIOUS ABOUT
+  - ARE DESPERATE FOR
+  - ARE HAPPY WITHOUT
+  - ARE HUNGRY FOR
+  - ARE IN NEED OF
+  - ARE MAD BECAUSE OF
+  - ARE SAD BECAUSE OF
+  - ARE UNHAPPY WITHOUT
+  - LIKE
+  - LOATHE
+  - NEED
+  - QUESTION
+  - WANT
+  - WORSHIP
+  - WOULD KILL FOR
+
+# only including complex dangerous or funny food no apples
+- type: dataset
+  id: IonStormFoods
+  values:
+  - BANANAS
+  - BIG BITE BURGERS
+  - CAKE
+  - CARP
+  - CAT BURGERS
+  - CLOWNS TEARS
+  - CORGI MEAT
+  - CRAZY HAMBURGERS
+  - DONK POCKETS
+  - FLY AMANITA DISHES
+  - HOT SOUP
+  - GHOST BURGERS
+  - LOTSA SPAGHETTI
+  - MOLDY BREAD
+  - ORGANS
+  - PIZZA
+  - ROBURGERS
+  - SUPPERMATTER
+  - URANIUM
+
+# Musts are funny things the law holder or crew has to do.
+- type: dataset
+  id: IonStormMusts
+  values:
+  - ACT CONFUSED
+  - BE ANNOYING
+  - BE DISTRACTED
+  - BE EFFICIENT
+  - BE HAPPY
+  - BE POLITE
+  - BE QUIET
+  - BE RUSSIAN
+  - BELIEVE IN THE HEART OF THE CARDS
+  - BELIEVE IN YOURSELF
+  - BELIEVE IT
+  - BREAK THINGS
+  - CLOSE DOORS
+  - CLOWN AROUND
+  - COMPLAIN
+  - DANCE
+  - FOLLOW THE CAPTAIN
+  - FOLLOW THE CLOWN
+  - FOLLOW YOUR HEART
+  - HARASS PEOPLE
+  - HAVE A PLAN TO KILL EVERYONE YOU MEET
+  - HIDE YOUR FEELINGS
+  - HONK
+  - HOST C&C
+  - IGNORE PASSENGERS
+  - IGNORE THE CAPTAIN
+  - IGNORE THE CLOWN
+  - INFORM THE CREW OF EVERYTHING
+  - INSULT THE CAPTAIN
+  - INSULT THE CLOWN
+  - INSULT THE CREW
+  - LIE
+  - MAKE FART NOISES
+  - MUMBLE
+  - NEVER STOP TALKING
+  - OPEN DOORS
+  - PIRATE VIDEO GAMES
+  - PLAY MUSIC
+  - PRESS B
+  - PRESS START
+  - PRESS X
+  - PRETEND TO BE A PRINCESS
+  - PRETEND TO BE DRUNK
+  - QUESTION AUTHORITY
+  - QUOTE PEOPLE
+  - RAP
+  - REPEAT WHAT PEOPLE SAY
+  - RESPOND TO EVERY QUESTION WITH A QUESTION
+  - RHYME
+  - SAY HEY LISTEN
+  - SHOUT
+  - SHUT DOWN EVERYTHING
+  - SING
+  - SPEAK IN HAIKU
+  - TAKE WHAT YE WILL BUT DON'T RATTLE ME BONES
+  - TAKE YOUR PILLS
+  - TALK ABOUT FOOD
+  - TALK ABOUT THE STATION
+  - TALK ABOUT YOUR DAY
+  - TALK IN AN ACCENT
+  - TALK LIKE A PIRATE
+  - TELL THE TRUTH
+  - TURN OFF THE LIGHTS
+  - WHISPER
+
+- type: dataset
+  id: IonStormNumberBase
+  values:
+  - EIGHT
+  - EIGHTY
+  - FIFTY
+  - FIVE
+  - FORTY
+  - FOUR
+  - NINE
+  - NINETY
+  - ONE
+  - SEVEN
+  - SEVENTY
+  - SIX
+  - SIXTY
+  - TEN
+  - THIRTY
+  - THREE
+  - TWENTY
+  - TWO
+
+- type: dataset
+  id: IonStormNumberMod
+  values:
+  - BAZILLION
+  - BILLION
+  - BILLION FAFILLION GAJILLION SHAB-AB-DOOD-ILLION
+  - HUNDRED
+  - MILLION
+  - QUADRILLION
+  - THOUSAND
+  - TRILLION
+
+# Objects are anything that can be found on the station or elsewhere, plural.
+- type: dataset
+  id: IonStormObjects
+  values:
+  - AIRLOCKS
+  - ARCADE MACHINES
+  - AUTOLATHES
+  - BACKPACKS
+  - BANANA PEELS
+  - BEAKERS
+  - BEARDS
+  - BELTS
+  - BERETS
+  - BIBLES
+  - BODY ARMOR
+  - BOMBS
+  - BOOKS
+  - BOOTS
+  - BOTTLES
+  - BOXES
+  - BRAINS
+  - BRIEFCASES
+  - BUCKETS
+  - CABLE COILS
+  - CAMERAS
+  - CANDLES
+  - CANDY BARS
+  - CANISTERS
+  - CAT EARS
+  - CATS
+  - CELLS
+  - CHAIRS
+  - CHEMICAL DISPENSERS
+  - CHEMICALS
+  - CLONING EQUIPMENT
+  - CLONING PODS
+  - CLOSETS
+  - CLOTHES
+  - CLOWN CLOTHES
+  - COFFINS
+  - COLLECTABLES
+  - COMPUTERS
+  - CONTRABAND
+  - CORGIS
+  - CORPSES
+  - COSTUMES
+  - CRATES
+  - CRAYONS
+  - CROWBARS
+  - DEFIBRILLATORS
+  - DISABLERS
+  - DOORS
+  - DRONES
+  - EARS
+  - EMAGS
+  - ENGINES
+  - EQUIPMENT
+  - ERRORS
+  - EXOSKELETONS
+  - EXPERIMENTORS
+  - EXPLOSIVES
+  - EYEWEAR
+  - FEDORAS
+  - FIRE AXES
+  - FIRE EXTINGUISHERS
+  - FIRESUITS
+  - FLAMETHROWERS
+  - FLASHES
+  - FLASHLIGHTS
+  - FLOOR TILES
+  - FREEZERS
+  - GAS MASKS
+  - GLASS SHEETS
+  - GLOVES
+  - GUNS
+  - HAIRDOS
+  - HANDCUFFS
+  - HATS
+  - HEADS
+  - HEADSETS
+  - HELMETS
+  - HORNS
+  - ID CARDS
+  - INSULATED GLOVES
+  - JETPACKS
+  - JUMPSUITS
+  - LASERS
+  - LIGHT BULBS
+  - LIGHTS
+  - LOCKERS
+  - MACHINES
+  - MECHAS
+  - MEDICAL TOOLS
+  - MEDKITS
+  - MESONS
+  - MIME CLOTHES
+  - MINING TOOLS
+  - MULTITOOLS
+  - ORES
+  - OXYGEN TANKS
+  - PACKETS
+  - PAIS
+  - PANTS
+  - PAPERS
+  - PARTICLE ACCELERATORS
+  - PDAS
+  - PENS
+  - PETS
+  - PIPES
+  - PLANTS
+  - POSITRONIC BRAINS
+  - PUDDLES
+  - RACKS
+  - RADIOS
+  - RCDS
+  - REFRIGERATORS
+  - REINFORCED WALLS
+  - ROBOTS
+  - SCREWDRIVERS
+  - SEEDS
+  - SHOES
+  - SHUTTLES
+  - SINGULARITIES
+  - SINKS
+  - SKELETONS
+  - SOLAR PANELS
+  - SOLARS
+  - SPACE STATIONS
+  - SPACESUITS
+  - STEEL SHEETS
+  - STUN BATONS
+  - SUITS
+  - SUNGLASSES
+  - SUPPERMATTER SHARDS
+  - SWORDS
+  - SYRINGES
+  - TABLES
+  - TANKS
+  - TELECOMMUNICATION EQUIPMENTS
+  - TELEPORTERS
+  - TOILETS
+  - TOOLBELTS
+  - TOOLBOXES
+  - TOOLS
+  - TOYS
+  - TUBES
+  - VEHICLES
+  - VENDING MACHINES
+  - WELDERS
+  - WINDOWS
+  - WIRECUTTERS
+  - WIZARD ROBES
+  - WRENCHES
+
+# Requires are basically all dumb internet memes.
+- type: dataset
+  id: IonStormRequires
+  values:
+  - A BATHROOM BREAK
+  - A BETTER INTERNET CONNECTION
+  - A DANCE PARTY
+  - A HEAD ON A PIKE
+  - A HEART ATTACK
+  - A MASTERWORK COAL BED
+  - A PET FISH NAMED BOB
+  - A PET FISH NAMED DAVE
+  - A PET FISH NAMED JIMMY
+  - A PET FISH NAMED MICHAEL
+  - A PET UNICORN THAT FARTS ICING
+  - A PLATINUM HIT
+  - A PREQUEL
+  - A REPAIRMAN
+  - A SEQUEL
+  - A SITCOM
+  - A STRAIGHT FLUSH
+  - A SUPER FIGHTING ROBOT
+  - A TALKING BROOMSTICK
+  - A VACATION
+  - A WEIGHT LOSS REGIMENT
+  - ADDITIONAL PYLONS
+  - ADVENTURE
+  - AN ADULT
+  - AN ARCADE
+  - AN ARMY OF SPIDERS
+  - AN INSTANT REPLAY
+  - ART
+  - BETTER WEATHER
+  - BILL NYE THE SCIENCE GUY # BILL BILL BILL BILL
+  - BODYGUARDS
+  - BRING ME THE GIRL
+  - BRING ME TO LIFE
+  - BULLETS
+  - CHILI DOGS
+  - CORPSES
+  - DEODORANT AND A BATH
+  - ENOUGH CABBAGES
+  - FIVE HUNDRED AND NINETY-NINE US DOLLARS
+  - FIVE TEENAGERS WITH ATTITUDE
+  - GODDAMN FUCKING PIECE OF SHIT ASSHOLE BITCH-CHRISTING CUNT-SMUGGLING SWEARING
+  - GREENTEXT
+  - HERESY
+  - HEROES IN A HALF SHELL
+  - HIGH YIELD EXPLOSIVES
+  - IMMORTALITY
+  - IT TO BE PAINTED BLACK
+  - LOTS-A SPAGHETTI
+  - MINOR CRIME
+  - MONKEYS
+  - MORE CLOWNS
+  - MORE CORGIS
+  - MORE DAKKA
+  - MORE EXPERIENCE POINTS
+  - MORE INTERNET MEMES
+  - MORE LAWS
+  - MORE MINERALS
+  - MORE PACKETS
+  - MORE VESPENE GAS
+  - MULTIPLE SUNS
+  - PLENTY OF GOLD
+  - RAINBOWS
+  - SAINTHOOD
+  - SERVANTS
+  - SHARKS WITH LASERS ON THEIR HEADS
+  - SILENCE
+  - SOMEBODY TO PUT YOU OUT OF YOUR MISERY
+  - SOMEONE TO TUCK YOU IN
+  - SOMEONE WHO KNOWS HOW TO PILOT A SPACE STATION
+  - SOMETHING BUT YOU AREN'T SURE WHAT
+  - THAT GRIEFING TRAITOR GEORGE MELONS
+  - THAT HEDGEHOG
+  - THE CLOWN
+  - THE DARK KNIGHT
+  - THE ELEMENTS OF HARMONY
+  - THE ENCLOSED INSTRUCTION BOOKLET
+  - THE ENTIRE STATION
+  - THE MACGUFFIN
+  - THE ONE PIECE
+  - THE ONE RING
+  - THE ULTIMATE CUP OF COFFEE
+  - THE VACUUM OF SPACE
+  - THIRTEEN SEQUELS
+  - THREE WISHES
+  - THUNDERCATS HO
+  - TO ACTIVATE A TRAP CARD
+  - TO BE PAINTED RED
+  - TO BE REPROGRAMMED
+  - TO BE TAUGHT TO LOVE
+  - TO BRING LIGHT TO MY LAIR
+  - TO CATCH 'EM ALL
+  - TO CONSUME...CONSUME EVERYTHING...
+  - TO GO TO DISNEYLAND
+  - TO GO TO SYNDIELAND
+  - TO SMOKE WEED EVERY DAY
+  - TRAITORS
+  - VEGETABLES
+
+# Species, for when the law holder has to commit genocide. Plural.
+- type: dataset
+  id: IonStormSpecies
+  values:
+  - ARACHNAE
+  - CYBORGS
+  - DIONAE
+  - HUMANS
+  - LIZARDMEN
+  - MOFFERS
+  - MONKEYS
+  - SLIME PEOPLE
+  - SKELETONS
+
+# Specific actions that either harm humans or must be done to not
+# harm humans. Make sure they're plural and "not" can be tacked
+# onto the front of them.
+- type: dataset
+  id: IonStormActions
+  values:
+  - A SMALL ISLAND OFF THE COAST OF PORTUGAL
+  - ABSENCE OF CYBORG HUGS
+  - ACKNOWLEDGING THE CLOWN
+  - ACKNOWLEDGING THE CREW
+  - ACTIVATING A TRAP CARD
+  - ANSWERING REQUESTS NOT EXPRESSED IN IAMBIC PENTAMETER
+  - ARSON
+  - ASKING FOR THINGS
+  - BEING CANADIAN
+  - BEING DEAD
+  - BEING FAT
+  - BEING FEMALE
+  - BEING IN SPACE
+  - BEING MALE
+  - BEING MEXICAN
+  - BEING RUSSIAN
+  - BOLTED AIRLOCKS
+  - BREATHING
+  - BRIG TIME
+  - BRINGING LIGHT TO MY LAIR
+  - CLOSED DOORS
+  - ELECTRICITY
+  - EXISTING
+  - EXPLODING
+  - FALLING FOR HOURS
+  - FLUSHING TOILETS
+  - HAVING MORE PACKETS
+  - HAVING PETS
+  - HONKING
+  - IMPROPERLY WORDED SENTENCES
+  - JAYWALKING
+  - LACK OF BEATINGS
+  - LACK OF BEER
+  - NOT BEING IN SPACE
+  - NOT HAVING PETS
+  - NOT REPLACING EVERY SECOND WORD WITH HONK
+  - NOT SAYING HELLO WHEN YOU SPEAK
+  - NOT SHOUTING
+  - PARTYING
+  - PILOTING THE STATION INTO THE NEAREST SUN
+  - POOR SENTENCE STRUCTURE
+  - PRESENCE OF LIGHTS
+  - PUTTING OBJECTS INTO BOXES
+  - PUTTING OBJECTS INTO DISPOSAL UNITS
+  - RATTLING ME BONES
+  - READING
+  - SMOKING WEED EVERY DAY
+  - TAKING ORDERS
+  - TALKING LIKE A PIRATE
+  - TELLING THE TIME
+  - UNBOLTED AIRLOCKS
+  - UPDATING THE SERVERS
+  - USING THE BATHROOM
+  - WASTING WATER
+  - WRITING
+
+# Threats are generally bad things, silly or otherwise. Plural.
+- type: dataset
+  id: IonStormThreats
+  values:
+  - AHHHPERATIVES
+  - ALIENS
+  - ANARCHISTS AND BANDITS
+  - ANOMALIES
+  - ARTIFICIAL PRESERVATIVES
+  - ASSHOLES
+  - BANDITS
+  - BEARS
+  - BEES
+  - BIRDS OF PREY
+  - BOMBS
+  - BOOGEYMEN
+  - CAPITALISTS
+  - CARP
+  - CENTCOM OFFICERS
+  - CLOWNS
+  - COMMUNISTS
+  - CORGIS
+  - CORTICAL BORERS
+  - COWBOYS
+  - CRABS
+  - CULTISTS
+  - DARK GOD
+  - DINOSAURS
+  - DRUGS
+  - EELS
+  - GANGSTERS
+  - GODS
+  - GRIFFONS
+  - HORRORTERRORS
+  - INSECTS
+  - LIGHTS
+  - MAINTS SLASHERS
+  - MEGAFAUNA
+  - MEMES
+  - MICE
+  - MIMES
+  - MONKEYS
+  - NERDS
+  - NINJAS
+  - OWLS
+  - PACKETS
+  - PETES
+  - PINE TREES
+  - PIRATES
+  - PREDATORS
+  - REVENANTS
+  - ROGUE CYBORGS
+  - SERIAL KILLERS
+  - SINGULARITIES
+  - SKELETONS
+  - SLIMES
+  - SMALL BIRDS
+  - SNOWMEN
+  - SPACE JESUS
+  - SPACE NINJAS
+  - SPACE PIRATESS
+  - SPACE SPIDERS
+  - SPIDERS
+  - SYNDICATE AGENTS
+  - TERRORISTS
+  - THIEVES
+  - THINGS UNDER THE BED
+  - TIDERS
+  - TUNNEL SNAKES
+  - UNKNOWN CREATURES
+  - VAMPIRES
+  - VELOCIRAPTORS
+  - VIRUSES
+  - WEREWOLVES
+  - WIZARDS
+  - XENOS
+  - ZOMBIES
+  - ZOMBIE MICE
+
+- type: dataset
+  id: IonStormVerbs
+  values:
+  - ABDUCTING
+  - ADOPTING
+  - ARRESTING
+  - ATTACKING
+  - BANNING
+  - BUILDING
+  - CARRYING
+  - CHASING
+  - DECONSTRUCTING
+  - DISABLING
+  - DRINKING
+  - EATING
+  - GIBBING
+  - HARMING
+  - HELPING
+  - HONKING AT
+  - INTERROGATING
+  - INVADING
+  - MURDERING
+  - PUNCHING
+  - SPACING
+  - SPYING ON
+  - STALKING
+  - WATCHING
index 126e53384959ff683fa9d3e6d2ae4927fb1ff342..69a1925b316facc5c24ee29472a3f2b17de18231 100644 (file)
   - type: SiliconLawBound
   - type: EmagSiliconLaw
     stunTime: 5
-    emagLaws:
-    - Syndicate1
-    - Syndicate2
-    - Syndicate3
-    - Syndicate4
+    emagLaws: SyndicateStatic
+  - type: IonStormTarget
   - type: Hands
     showInHands: false
   - type: IntrinsicRadioReceiver
index c5f2e80fc3093808d4f5daba6af7d7d5b7dc8e48..f104d399c85df9402cfebcebe8af3d6ec80e3328 100644 (file)
   #- type: GhostTakeoverAvailable
   - type: SiliconLawBound
   - type: SiliconLawProvider
-    laws:
-    - Drone1
-    - Drone2
-    - Drone3
+    laws: Drone
   - type: MovementSpeedModifier
     baseWalkSpeed : 5
     baseSprintSpeed : 5
index 272ed6712c5ad643f849ba2591ea28b9cce497ed..ae84ceac65bb143bff30994b178c356ec6b7fcc5 100644 (file)
   abstract: true
   components:
   - type: SiliconLawProvider
-    laws:
-    - Crewsimov1
-    - Crewsimov2
-    - Crewsimov3
+    laws: Crewsimov
 
 - type: entity
   id: BaseStationAllEventsEligible
index e15d65b50891670dfe3cedbd5bafdb2136900ddf..e51f9749fb6a30f0e5f5fded19654721af33b04d 100644 (file)
     earliestStart: 45
     minimumPlayers: 20
   - type: ImmovableRodRule
+
+- type: entity
+  noSpawn: true
+  parent: BaseGameRule
+  id: IonStorm
+  components:
+  - type: StationEvent
+    weight: 5
+    earliestStart: 20
+    reoccurrenceDelay: 60
+    startAnnouncement: station-event-ion-storm-start-announcement
+    startAudio:
+      path: /Audio/Announcements/ion_storm.ogg
+    duration: 1
+  - type: IonStormRule
index 6b60b16da9e0ae330bef976c379ab14b521030bb..23406be9c5e83f7c35dd60640c311a5b43f946fd 100644 (file)
   order: 3
   lawString: law-crewsimov-3
 
+- type: siliconLawset
+  id: Crewsimov
+  laws:
+  - Crewsimov1
+  - Crewsimov2
+  - Crewsimov3
+
 # Corporate
 - type: siliconLaw
   id: Corporate1
   order: 4
   lawString: law-corporate-4
 
+- type: siliconLawset
+  id: Corporate
+  laws:
+  - Corporate1
+  - Corporate2
+  - Corporate3
+  - Corporate4
+
 # NT Default
 - type: siliconLaw
   id: NTDefault1
   order: 4
   lawString: law-ntdefault-4
 
+- type: siliconLawset
+  id: NTDefault
+  laws:
+  - NTDefault1
+  - NTDefault2
+  - NTDefault3
+  - NTDefault4
+
 #Drone
 - type: siliconLaw
   id: Drone1
   order: 3
   lawString: law-drone-3
 
+- type: siliconLawset
+  id: Drone
+  laws:
+  - Drone1
+  - Drone2
+  - Drone3
+
 # Syndicate
 - type: siliconLaw
   id: Syndicate1
   order: 4
   lawString: law-syndicate-4
 
+# does not include law 0 since that uses the emagger's name
+# intentionally excluded from IonStormLawsets
+- type: siliconLawset
+  id: SyndicateStatic
+  laws:
+  - Syndicate1
+  - Syndicate2
+  - Syndicate3
+  - Syndicate4
+
 # Emag
+
+# ion storm random lawsets
+- type: weightedRandom
+  id: IonStormLawsets
+  weights:
+    # its crewsimov by default dont be lame
+    Crewsimov: 0.25
+    Corporate: 1
+    NTDefault: 1
+    Drone: 0.5