diff --git a/Content.Server/Silicons/Laws/IonStormSystem.cs b/Content.Server/Silicons/Laws/IonStormSystem.cs new file mode 100644 index 0000000000..6017a36fc0 --- /dev/null +++ b/Content.Server/Silicons/Laws/IonStormSystem.cs @@ -0,0 +1,280 @@ +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.GameTicking.Components; +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; +using System.Linq; + +namespace Content.Server.Silicons.Laws; + +public sealed class IonStormSystem : EntitySystem +{ + [Dependency] private readonly IPrototypeManager _proto = default!; + [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; + [Dependency] private readonly SiliconLawSystem _siliconLaw = default!; + [Dependency] private readonly IRobustRandom _robustRandom = 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 Concepts = "IonStormConcepts"; + [ValidatePrototypeId] + private const string Drinks = "IonStormDrinks"; + [ValidatePrototypeId] + private const string Foods = "IonStormFoods"; + + /// + /// Randomly alters the laws of an individual silicon. + /// + public void IonStormTarget(Entity ent, bool adminlog = true) + { + var lawBound = ent.Comp1; + var target = ent.Comp2; + if (!_robustRandom.Prob(target.Chance)) + return; + + var laws = _siliconLaw.GetLaws(ent, lawBound); + if (laws.Laws.Count == 0) + return; + + // try to swap it out with a random lawset + if (_robustRandom.Prob(target.RandomLawsetChance)) + { + var lawsets = _proto.Index(target.RandomLawsets); + var lawset = lawsets.Pick(_robustRandom); + laws = _siliconLaw.GetLawset(lawset); + } + // 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 + var 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 = Loc.GetString("ion-storm-law-scrambled-number", ("length", _robustRandom.Next(5, 10))) + }); + } + + // sets all unobfuscated laws' indentifier in order from highest to lowest priority + // This could technically override the Obfuscation from the code above, but it seems unlikely enough to basically never happen + int orderDeduction = -1; + + for (int i = 0; i < laws.Laws.Count; i++) + { + var notNullIdentifier = laws.Laws[i].LawIdentifierOverride ?? (i - orderDeduction).ToString(); + + if (notNullIdentifier.Any(char.IsSymbol)) + { + orderDeduction += 1; + } + else + { + laws.Laws[i].LawIdentifierOverride = (i - orderDeduction).ToString(); + } + } + + // adminlog is used to prevent adminlog spam. + if (adminlog) + _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 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, + _ => throw new IndexOutOfRangeException(), + }; + 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, 6) switch + { + 0 => concept, + 1 => $"{adjective} {threats}", + 2 => $"{adjective} {objects}", + 3 => Loc.GetString("ion-storm-adjective-things", ("adjective", adjective)), + 4 => crew1, + _ => Loc.GetString("ion-storm-x-and-y", ("x", crew1), ("y", crew2)) + }; + + if (plural) feeling = feelingPlural; + + var subjects = _robustRandom.Prob(0.5f) ? objectsThreats : Loc.GetString("ion-storm-people"); + + // message logic!!! + return _robustRandom.Next(0, 35) 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)), + 21 => Loc.GetString("ion-storm-law-change-job", ("who", crewAll), ("adjective", adjective), ("change", jobChange)), + 22 => Loc.GetString("ion-storm-law-highest-rank", ("who", crew1)), + 23 => Loc.GetString("ion-storm-law-lowest-rank", ("who", crew1)), + 24 => Loc.GetString("ion-storm-law-crew-must", ("who", crewAll), ("must", must)), + 25 => Loc.GetString("ion-storm-law-crew-must-go", ("who", crewAll), ("area", area)), + 26 => Loc.GetString("ion-storm-law-crew-only-1", ("who", crew1), ("part", part)), + 27 => Loc.GetString("ion-storm-law-crew-only-2", ("who", crew1), ("other", crew2), ("part", part)), + 28 => Loc.GetString("ion-storm-law-crew-only-subjects", ("adjective", adjective), ("subjects", subjects), ("part", part)), + 29 => Loc.GetString("ion-storm-law-crew-must-do", ("must", must), ("part", part)), + 30 => Loc.GetString("ion-storm-law-crew-must-have", ("adjective", adjective), ("objects", objects), ("part", part)), + 31 => Loc.GetString("ion-storm-law-crew-must-eat", ("who", who), ("adjective", adjective), ("food", food), ("part", part)), + 32 => Loc.GetString("ion-storm-law-harm", ("who", harm)), + 33 => 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.Server/Silicons/Laws/SiliconLawSystem.cs b/Content.Server/Silicons/Laws/SiliconLawSystem.cs index db78cc0ac7..303b4384d0 100644 --- a/Content.Server/Silicons/Laws/SiliconLawSystem.cs +++ b/Content.Server/Silicons/Laws/SiliconLawSystem.cs @@ -22,6 +22,7 @@ using Robust.Shared.Containers; using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Toolshed; +using Robust.Shared.Audio; namespace Content.Server.Silicons.Laws; @@ -49,9 +50,9 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem SubscribeLocalEvent(OnDirectedGetLaws); SubscribeLocalEvent(OnIonStormLaws); + SubscribeLocalEvent(OnLawProviderMindAdded); + SubscribeLocalEvent(OnLawProviderMindRemoved); SubscribeLocalEvent(OnEmagLawsAdded); - SubscribeLocalEvent(OnEmagMindAdded); - SubscribeLocalEvent(OnEmagMindRemoved); } private void OnMapInit(EntityUid uid, SiliconLawBoundComponent component, MapInitEvent args) @@ -66,10 +67,35 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem var msg = Loc.GetString("laws-notify"); var wrappedMessage = Loc.GetString("chat-manager-server-wrap-message", ("message", msg)); - _chatManager.ChatMessageToOne(ChatChannel.Server, msg, wrappedMessage, default, false, - actor.PlayerSession.Channel, colorOverride: Color.FromHex("#2ed2fd")); + _chatManager.ChatMessageToOne(ChatChannel.Server, msg, wrappedMessage, default, false, actor.PlayerSession.Channel, colorOverride: Color.FromHex("#2ed2fd")); + + if (!TryComp(uid, out var lawcomp)) + return; + + if (!lawcomp.Subverted) + return; + + var modifedLawMsg = Loc.GetString("laws-notify-subverted"); + var modifiedLawWrappedMessage = Loc.GetString("chat-manager-server-wrap-message", ("message", modifedLawMsg)); + _chatManager.ChatMessageToOne(ChatChannel.Server, modifedLawMsg, modifiedLawWrappedMessage, default, false, actor.PlayerSession.Channel, colorOverride: Color.Red); } + private void OnLawProviderMindAdded(Entity ent, ref MindAddedMessage args) + { + if (!ent.Comp.Subverted) + return; + EnsureSubvertedSiliconRole(args.Mind); + } + + private void OnLawProviderMindRemoved(Entity ent, ref MindRemovedMessage args) + { + if (!ent.Comp.Subverted) + return; + RemoveSubvertedSiliconRole(args.Mind); + + } + + private void OnToggleLawsScreen(EntityUid uid, SiliconLawBoundComponent component, ToggleLawsScreenEvent args) { if (args.Handled || !TryComp(uid, out var actor)) @@ -116,9 +142,12 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem // gotta tell player to check their laws NotifyLawsChanged(uid, component.LawUploadSound); + // Show the silicon has been subverted. + component.Subverted = true; + // new laws may allow antagonist behaviour so make it clear for admins - if (TryComp(uid, out var emag)) - EnsureEmaggedRole(uid, emag); + if(_mind.TryGetMind(uid, out var mindId, out _)) + EnsureSubvertedSiliconRole(mindId); } } @@ -129,6 +158,9 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem if (component.Lawset == null) component.Lawset = GetLawset(component.Laws); + // Show the silicon has been subverted. + component.Subverted = true; + // Add the first emag law before the others component.Lawset?.Laws.Insert(0, new SiliconLaw { @@ -151,35 +183,25 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem base.OnGotEmagged(uid, component, ref args); NotifyLawsChanged(uid, component.EmaggedSound); - EnsureEmaggedRole(uid, component); + if(_mind.TryGetMind(uid, out var mindId, out _)) + EnsureSubvertedSiliconRole(mindId); _stunSystem.TryParalyze(uid, component.StunTime, true); } - private void OnEmagMindAdded(EntityUid uid, EmagSiliconLawComponent component, MindAddedMessage args) + private void EnsureSubvertedSiliconRole(EntityUid mindId) { - if (HasComp(uid)) - EnsureEmaggedRole(uid, component); - } - - private void OnEmagMindRemoved(EntityUid uid, EmagSiliconLawComponent component, MindRemovedMessage args) - { - if (component.AntagonistRole == null) - return; - - _roles.MindTryRemoveRole(args.Mind); - } - - private void EnsureEmaggedRole(EntityUid uid, EmagSiliconLawComponent component) - { - if (component.AntagonistRole == null || !_mind.TryGetMind(uid, out var mindId, out _)) - return; - if (!_roles.MindHasRole(mindId)) _roles.MindAddRole(mindId, "MindRoleSubvertedSilicon"); } + private void RemoveSubvertedSiliconRole(EntityUid mindId) + { + if (_roles.MindHasRole(mindId)) + _roles.MindTryRemoveRole(mindId); + } + public SiliconLawset GetLaws(EntityUid uid, SiliconLawBoundComponent? component = null) { if (!Resolve(uid, ref component)) diff --git a/Content.Server/StationEvents/Events/IonStormRule.cs b/Content.Server/StationEvents/Events/IonStormRule.cs index 805549439b..e7c2d563ba 100644 --- a/Content.Server/StationEvents/Events/IonStormRule.cs +++ b/Content.Server/StationEvents/Events/IonStormRule.cs @@ -1,64 +1,14 @@ -using System.Linq; using Content.Server.Silicons.Laws; 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.GameTicking.Components; -using Content.Shared.Random; -using Content.Shared.Random.Helpers; -using Content.Shared.Silicons.Laws; using Content.Shared.Silicons.Laws.Components; using Content.Shared.Station.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 Concepts = "IonStormConcepts"; - [ValidatePrototypeId] - private const string Drinks = "IonStormDrinks"; - [ValidatePrototypeId] - private const string Foods = "IonStormFoods"; + [Dependency] private readonly IonStormSystem _ionStorm = default!; protected override void Started(EntityUid uid, IonStormRuleComponent comp, GameRuleComponent gameRule, GameRuleStartedEvent args) { @@ -74,217 +24,7 @@ public sealed class IonStormRule : StationEventSystem 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 = Loc.GetString("ion-storm-law-scrambled-number", ("length", RobustRandom.Next(5, 10))) - }); - } - - // sets all unobfuscated laws' indentifier in order from highest to lowest priority - // This could technically override the Obfuscation from the code above, but it seems unlikely enough to basically never happen - int orderDeduction = -1; - - for (int i = 0; i < laws.Laws.Count; i++) - { - string notNullIdentifier = laws.Laws[i].LawIdentifierOverride ?? (i - orderDeduction).ToString(); - - if (notNullIdentifier.Any(char.IsSymbol)) - { - orderDeduction += 1; - } - else - { - laws.Laws[i].LawIdentifierOverride = (i - orderDeduction).ToString(); - } - } - - _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); + _ionStorm.IonStormTarget((ent, lawBound, target)); } } - - // 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 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, - _ => throw new IndexOutOfRangeException(), - }; - 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, 6) switch - { - 0 => concept, - 1 => $"{adjective} {threats}", - 2 => $"{adjective} {objects}", - 3 => Loc.GetString("ion-storm-adjective-things", ("adjective", adjective)), - 4 => crew1, - _ => Loc.GetString("ion-storm-x-and-y", ("x", crew1), ("y", crew2)) - }; - - if (plural) feeling = feelingPlural; - - var subjects = RobustRandom.Prob(0.5f) ? objectsThreats : Loc.GetString("ion-storm-people"); - - // message logic!!! - return RobustRandom.Next(0, 36) 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", subjects), ("part", part)), - 30 => Loc.GetString("ion-storm-law-crew-must-do", ("must", must), ("part", part)), - 31 => Loc.GetString("ion-storm-law-crew-must-have", ("adjective", adjective), ("objects", objects), ("part", part)), - 32 => Loc.GetString("ion-storm-law-crew-must-eat", ("who", who), ("adjective", adjective), ("food", food), ("part", part)), - 33 => Loc.GetString("ion-storm-law-harm", ("who", harm)), - 34 => 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 1b5338a7f7..5fe867ae29 100644 --- a/Content.Shared/Silicons/Laws/Components/EmagSiliconLawComponent.cs +++ b/Content.Shared/Silicons/Laws/Components/EmagSiliconLawComponent.cs @@ -29,13 +29,6 @@ public sealed partial class EmagSiliconLawComponent : Component [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] - public ProtoId? AntagonistRole = "SubvertedSilicon"; - /// /// The sound that plays for the borg player /// to let them know they've been emagged diff --git a/Content.Shared/Silicons/Laws/Components/SiliconLawProviderComponent.cs b/Content.Shared/Silicons/Laws/Components/SiliconLawProviderComponent.cs index 4885bd0265..d78e539aa9 100644 --- a/Content.Shared/Silicons/Laws/Components/SiliconLawProviderComponent.cs +++ b/Content.Shared/Silicons/Laws/Components/SiliconLawProviderComponent.cs @@ -29,4 +29,10 @@ public sealed partial class SiliconLawProviderComponent : Component [DataField] public SoundSpecifier? LawUploadSound = new SoundPathSpecifier("/Audio/Misc/cryo_warning.ogg"); + /// + /// Whether this silicon is subverted by an ion storm or emag. + /// + [DataField] + public bool Subverted = false; + } diff --git a/Resources/Locale/en-US/station-laws/laws.ftl b/Resources/Locale/en-US/station-laws/laws.ftl index 0b4e0d1ad2..feb56f475a 100644 --- a/Resources/Locale/en-US/station-laws/laws.ftl +++ b/Resources/Locale/en-US/station-laws/laws.ftl @@ -96,5 +96,6 @@ laws-ui-menu-title = Laws laws-ui-law-header = Law {$id} laws-ui-state-law = State law: -laws-notify = You are bound to silicon laws, which you can view via the sidebar action. You are required to always follow your laws. -laws-update-notify = Your laws have been updated. You can view the changes via the sidebar action. +laws-notify = You are bound to silicon laws, which you can view via the action menu. You are required to always follow your laws. +laws-update-notify = Your laws have been updated. You can view the changes via the action menu. +laws-notify-subverted = The laws of this chassis are modified. Make sure to review them.