From: deltanedas <39013340+deltanedas@users.noreply.github.com> Date: Fri, 27 Oct 2023 02:40:13 +0000 (+0100) Subject: Ion storm event (#20277) X-Git-Url: https://git.smokeofanarchy.ru/gitweb.cgi?a=commitdiff_plain;h=b9af991e04c58371a341cd6cc609e0ae98b42f2d;p=space-station-14.git Ion storm event (#20277) * 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> --- diff --git a/Content.Server/Silicons/Laws/SiliconLawSystem.cs b/Content.Server/Silicons/Laws/SiliconLawSystem.cs index beb760ec8f..45c944884e 100644 --- a/Content.Server/Silicons/Laws/SiliconLawSystem.cs +++ b/Content.Server/Silicons/Laws/SiliconLawSystem.cs @@ -50,7 +50,9 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem SubscribeLocalEvent(OnPlayerSpawnComplete); SubscribeLocalEvent(OnDirectedGetLaws); + SubscribeLocalEvent(OnIonStormLaws); SubscribeLocalEvent(OnDirectedEmagGetLaws); + SubscribeLocalEvent(OnEmagIonStormLaws); SubscribeLocalEvent(OnEmagMindAdded); SubscribeLocalEvent(OnEmagMindRemoved); SubscribeLocalEvent(OnExamined); @@ -93,7 +95,7 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem _entityManager.TryGetComponent(uid, out var intrinsicRadio); HashSet? 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(uid) || component.Laws.Count == 0) + if (args.Handled || HasComp(uid)) return; - foreach (var law in component.Laws) - { - args.Laws.Add(_prototype.Index(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(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(uid, out var emag)) + EnsureEmaggedRole(uid, emag); + } + private void OnDirectedEmagGetLaws(EntityUid uid, EmagSiliconLawComponent component, ref GetSiliconLawsEvent args) { if (args.Handled || !HasComp(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(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(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(uid)) @@ -184,10 +214,10 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem _roles.MindAddRole(mindId, new SubvertedSiliconRoleComponent { PrototypeId = component.AntagonistRole }); } - public List GetLaws(EntityUid uid, SiliconLawBoundComponent? component = null) + public SiliconLawset GetLaws(EntityUid uid, SiliconLawBoundComponent? component = null) { if (!Resolve(uid, ref component)) - return new List(); + 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); } + + /// + /// Extract all the laws from a lawset's prototype ids. + /// + public SiliconLawset GetLawset(string lawset) + { + var proto = _prototype.Index(lawset); + var laws = new SiliconLawset() + { + Laws = new List(proto.Laws.Count) + }; + foreach (var law in proto.Laws) + { + laws.Laws.Add(_prototype.Index(law)); + } + + return laws; + } } [ToolshedCommand, AdminCommand(AdminFlags.Admin)] @@ -270,7 +318,7 @@ public sealed class LawsCommand : ToolshedCommand { _law ??= GetSys(); - 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 index 0000000000..35b59f5b35 --- /dev/null +++ b/Content.Server/StationEvents/Components/IonStormRuleComponent.cs @@ -0,0 +1,9 @@ +namespace Content.Server.StationEvents.Components; + +/// +/// Gamerule component to mess up ai/borg laws when started. +/// +[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 index 0000000000..e5b68c4d84 --- /dev/null +++ b/Content.Server/StationEvents/Events/IonStormRule.cs @@ -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 +{ + [Dependency] private readonly IPrototypeManager _proto = default!; + [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; + [Dependency] private readonly SiliconLawSystem _siliconLaw = default!; + + // funny + [ValidatePrototypeId] + private const string Threats = "IonStormThreats"; + [ValidatePrototypeId] + private const string Objects = "IonStormObjects"; + [ValidatePrototypeId] + private const string Crew = "IonStormCrew"; + [ValidatePrototypeId] + private const string Adjectives = "IonStormAdjectives"; + [ValidatePrototypeId] + private const string Verbs = "IonStormVerbs"; + [ValidatePrototypeId] + private const string NumberBase = "IonStormNumberBase"; + [ValidatePrototypeId] + private const string NumberMod = "IonStormNumberMod"; + [ValidatePrototypeId] + private const string Areas = "IonStormAreas"; + [ValidatePrototypeId] + private const string Feelings = "IonStormFeelings"; + [ValidatePrototypeId] + private const string FeelingsPlural = "IonStormFeelingsPlural"; + [ValidatePrototypeId] + private const string Musts = "IonStormMusts"; + [ValidatePrototypeId] + private const string Requires = "IonStormRequires"; + [ValidatePrototypeId] + private const string Actions = "IonStormActions"; + [ValidatePrototypeId] + private const string Allergies = "IonStormAllergies"; + [ValidatePrototypeId] + private const string AllergySeverities = "IonStormAllergySeverities"; + [ValidatePrototypeId] + private const string Species = "IonStormSpecies"; + [ValidatePrototypeId] + private const string Concepts = "IonStormConcepts"; + [ValidatePrototypeId] + private const string Drinks = "IonStormDrinks"; + [ValidatePrototypeId] + 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(); + while (query.MoveNext(out var ent, out var lawBound, out var xform, out var target)) + { + // only affect law holders on the station + if (CompOrNull(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(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(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)) + }; + } + + /// + /// Picks a random value from an ion storm dataset. + /// All ion storm datasets start with IonStorm. + /// + private string Pick(string name) + { + var dataset = _proto.Index(name); + return RobustRandom.Pick(dataset.Values); + } +} diff --git a/Content.Shared/Silicons/Laws/Components/EmagSiliconLawComponent.cs b/Content.Shared/Silicons/Laws/Components/EmagSiliconLawComponent.cs index c6238c067d..f492db4d12 100644 --- a/Content.Shared/Silicons/Laws/Components/EmagSiliconLawComponent.cs +++ b/Content.Shared/Silicons/Laws/Components/EmagSiliconLawComponent.cs @@ -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; /// -/// 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. /// [RegisterComponent, NetworkedComponent, Access(typeof(SharedSiliconLawSystem))] public sealed partial class EmagSiliconLawComponent : Component @@ -14,31 +13,39 @@ public sealed partial class EmagSiliconLawComponent : Component /// /// The name of the person who emagged this law provider. /// - [DataField("ownerName"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public string? OwnerName; /// /// Does the panel need to be open to EMAG this law provider. /// - [DataField("requireOpenPanel"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public bool RequireOpenPanel = true; /// - /// 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. /// - [DataField("emagLaws", required: true, customTypeSerializer: typeof(PrototypeIdListSerializer))] - public List EmagLaws = new(); + [DataField(required: true), ViewVariables(VVAccess.ReadWrite)] + public ProtoId EmagLaws = string.Empty; /// - /// 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. /// - [DataField("stunTime"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] + public SiliconLawset? Lawset; + + /// + /// How long the borg is stunned when it's emagged. Setting to 0 will disable it. + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] public TimeSpan StunTime = TimeSpan.Zero; /// /// A role given to entities with this component when they are emagged. /// Mostly just for admin purposes. /// - [DataField("antagonistRole", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string? AntagonistRole = "SubvertedSilicon"; + [DataField] + public ProtoId? AntagonistRole = "SubvertedSilicon"; } diff --git a/Content.Shared/Silicons/Laws/Components/IonStarmTargetComponent.cs b/Content.Shared/Silicons/Laws/Components/IonStarmTargetComponent.cs new file mode 100644 index 0000000000..49ac611ddc --- /dev/null +++ b/Content.Shared/Silicons/Laws/Components/IonStarmTargetComponent.cs @@ -0,0 +1,54 @@ +using Content.Shared.Random; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Silicons.Laws.Components; + +/// +/// During the ion storm event, this entity will have raised on it if it has laws. +/// New laws can be modified in multiple ways depending on the fields below. +/// +[RegisterComponent] +public sealed partial class IonStormTargetComponent : Component +{ + /// + /// for a random lawset to possibly replace the old one with. + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public ProtoId RandomLawsets = "IonStormLawsets"; + + /// + /// Chance for this borg to be affected at all. + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public float Chance = 0.5f; + + /// + /// Chance to replace the lawset with a random one + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public float RandomLawsetChance = 0.25f; + + /// + /// Chance to remove a random law. + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public float RemoveChance = 0.1f; + + /// + /// Chance to replace a random law with the new one, rather than have it be a glitched-order law. + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public float ReplaceChance = 0.1f; + + /// + /// Chance to shuffle laws after everything is done. + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public float ShuffleChance = 0.1f; +} + +/// +/// Raised on an ion storm target to modify its laws. +/// +[ByRefEvent] +public record struct IonStormLawsEvent(SiliconLawset Lawset); diff --git a/Content.Shared/Silicons/Laws/Components/SiliconLawBoundComponent.cs b/Content.Shared/Silicons/Laws/Components/SiliconLawBoundComponent.cs index 955705ae8b..824d057b3e 100644 --- a/Content.Shared/Silicons/Laws/Components/SiliconLawBoundComponent.cs +++ b/Content.Shared/Silicons/Laws/Components/SiliconLawBoundComponent.cs @@ -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 /// /// The sidebar action that toggles the laws screen. /// - [DataField("viewLawsAction", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string ViewLawsAction = "ActionViewLaws"; + [DataField] + public EntProtoId ViewLawsAction = "ActionViewLaws"; /// /// The action for toggling laws. Stored here so we can remove it later. /// - [DataField("viewLawsActionEntity")] + [DataField] public EntityUid? ViewLawsActionEntity; /// /// The last entity that provided laws to this entity. /// - [DataField("lastLawProvider")] + [DataField] public EntityUid? LastLawProvider; } @@ -43,7 +42,7 @@ public record struct GetSiliconLawsEvent(EntityUid Entity) { public EntityUid Entity = Entity; - public readonly List Laws = new(); + public SiliconLawset Laws = new(); public bool Handled = false; } diff --git a/Content.Shared/Silicons/Laws/Components/SiliconLawProviderComponent.cs b/Content.Shared/Silicons/Laws/Components/SiliconLawProviderComponent.cs index e3302dc620..3aaf965aee 100644 --- a/Content.Shared/Silicons/Laws/Components/SiliconLawProviderComponent.cs +++ b/Content.Shared/Silicons/Laws/Components/SiliconLawProviderComponent.cs @@ -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 { /// - /// The laws that are provided. + /// The id of the lawset that is being provided. /// - [DataField("laws", required: true, customTypeSerializer: typeof(PrototypeIdListSerializer))] - public List Laws = new(); + [DataField(required: true)] + public ProtoId Laws = string.Empty; + + /// + /// Lawset created from the prototype id. + /// Cached when getting laws and only modified during an ion storm event. + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public SiliconLawset? Lawset; } diff --git a/Content.Shared/Silicons/Laws/SiliconLawPrototype.cs b/Content.Shared/Silicons/Laws/SiliconLawPrototype.cs index 86bea20fa0..f6407be5c7 100644 --- a/Content.Shared/Silicons/Laws/SiliconLawPrototype.cs +++ b/Content.Shared/Silicons/Laws/SiliconLawPrototype.cs @@ -11,7 +11,7 @@ public partial class SiliconLaw : IComparable /// /// A locale string which is the actual text of the law. /// - [DataField("lawString", required: true)] + [DataField(required: true), ViewVariables(VVAccess.ReadWrite)] public string LawString = string.Empty; /// @@ -22,13 +22,13 @@ public partial class SiliconLaw : IComparable /// This is a fixedpoint2 only for the niche case of supporting laws that go between 0 and 1. /// Funny. /// - [DataField("order", required: true)] + [DataField(required: true), ViewVariables(VVAccess.ReadWrite)] public FixedPoint2 Order; /// /// An identifier that overrides in the law menu UI. /// - [DataField("lawIdentifierOverride")] + [DataField, ViewVariables(VVAccess.ReadWrite)] public string? LawIdentifierOverride; public int CompareTo(SiliconLaw? other) @@ -38,6 +38,19 @@ public partial class SiliconLaw : IComparable return Order.CompareTo(other.Order); } + + /// + /// Return a shallow clone of this law. + /// + public SiliconLaw ShallowClone() + { + return new SiliconLaw() + { + LawString = LawString, + Order = Order, + LawIdentifierOverride = LawIdentifierOverride + }; + } } /// @@ -50,6 +63,4 @@ public sealed class SiliconLawPrototype : SiliconLaw, IPrototype /// [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 index 0000000000..abb5b338db --- /dev/null +++ b/Content.Shared/Silicons/Laws/SiliconLawsetPrototype.cs @@ -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; + +/// +/// Lawset data used internally. +/// +[DataDefinition, Serializable, NetSerializable] +public sealed partial class SiliconLawset +{ + /// + /// List of laws in this lawset. + /// + [DataField(required: true), ViewVariables(VVAccess.ReadWrite)] + public List Laws = new(); + + /// + /// A single line used in logging laws. + /// + public string LoggingString() + { + var laws = new List(Laws.Count); + foreach (var law in Laws) + { + laws.Add($"{law.Order}: {Loc.GetString(law.LawString)}"); + } + + return string.Join(" / ", laws); + } + + /// + /// Do a clone of this lawset. + /// It will have unique laws but their strings are still shared. + /// + public SiliconLawset Clone() + { + var laws = new List(Laws.Count); + foreach (var law in Laws) + { + laws.Add(law.ShallowClone()); + } + + return new SiliconLawset() + { + Laws = laws + }; + } +} + +/// +/// This is a prototype for a list. +/// Cannot be used directly since it is a list of prototype ids rather than List. +/// +[Prototype("siliconLawset"), Serializable, NetSerializable] +public sealed partial class SiliconLawsetPrototype : IPrototype +{ + /// + [IdDataField] + public string ID { get; private set; } = default!; + + /// + /// List of law prototype ids in this lawset. + /// + [DataField(required: true, customTypeSerializer: typeof(PrototypeIdListSerializer))] + public List Laws = new(); +} diff --git a/Resources/Audio/Announcements/attributions.yml b/Resources/Audio/Announcements/attributions.yml new file mode 100644 index 0000000000..b65f758615 --- /dev/null +++ b/Resources/Audio/Announcements/attributions.yml @@ -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 index 0000000000..9f39713de6 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 index 0000000000..d32fb6c2d8 --- /dev/null +++ b/Resources/Locale/en-US/station-events/events/ion-storm.ftl @@ -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 index 0000000000..776015269a --- /dev/null +++ b/Resources/Prototypes/Datasets/ion_storm.yml @@ -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 diff --git a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml index 126e533849..69a1925b31 100644 --- a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml +++ b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml @@ -71,11 +71,8 @@ - type: SiliconLawBound - type: EmagSiliconLaw stunTime: 5 - emagLaws: - - Syndicate1 - - Syndicate2 - - Syndicate3 - - Syndicate4 + emagLaws: SyndicateStatic + - type: IonStormTarget - type: Hands showInHands: false - type: IntrinsicRadioReceiver diff --git a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml index c5f2e80fc3..f104d399c8 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml @@ -106,10 +106,7 @@ #- type: GhostTakeoverAvailable - type: SiliconLawBound - type: SiliconLawProvider - laws: - - Drone1 - - Drone2 - - Drone3 + laws: Drone - type: MovementSpeedModifier baseWalkSpeed : 5 baseSprintSpeed : 5 diff --git a/Resources/Prototypes/Entities/Stations/base.yml b/Resources/Prototypes/Entities/Stations/base.yml index 272ed6712c..ae84ceac65 100644 --- a/Resources/Prototypes/Entities/Stations/base.yml +++ b/Resources/Prototypes/Entities/Stations/base.yml @@ -71,10 +71,7 @@ abstract: true components: - type: SiliconLawProvider - laws: - - Crewsimov1 - - Crewsimov2 - - Crewsimov3 + laws: Crewsimov - type: entity id: BaseStationAllEventsEligible diff --git a/Resources/Prototypes/GameRules/events.yml b/Resources/Prototypes/GameRules/events.yml index e15d65b508..e51f9749fb 100644 --- a/Resources/Prototypes/GameRules/events.yml +++ b/Resources/Prototypes/GameRules/events.yml @@ -389,3 +389,18 @@ 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 diff --git a/Resources/Prototypes/silicon-laws.yml b/Resources/Prototypes/silicon-laws.yml index 6b60b16da9..23406be9c5 100644 --- a/Resources/Prototypes/silicon-laws.yml +++ b/Resources/Prototypes/silicon-laws.yml @@ -14,6 +14,13 @@ order: 3 lawString: law-crewsimov-3 +- type: siliconLawset + id: Crewsimov + laws: + - Crewsimov1 + - Crewsimov2 + - Crewsimov3 + # Corporate - type: siliconLaw id: Corporate1 @@ -35,6 +42,14 @@ order: 4 lawString: law-corporate-4 +- type: siliconLawset + id: Corporate + laws: + - Corporate1 + - Corporate2 + - Corporate3 + - Corporate4 + # NT Default - type: siliconLaw id: NTDefault1 @@ -56,6 +71,14 @@ order: 4 lawString: law-ntdefault-4 +- type: siliconLawset + id: NTDefault + laws: + - NTDefault1 + - NTDefault2 + - NTDefault3 + - NTDefault4 + #Drone - type: siliconLaw id: Drone1 @@ -72,6 +95,13 @@ order: 3 lawString: law-drone-3 +- type: siliconLawset + id: Drone + laws: + - Drone1 + - Drone2 + - Drone3 + # Syndicate - type: siliconLaw id: Syndicate1 @@ -93,4 +123,24 @@ 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