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);
_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);
}
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))
_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);
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)]
{
_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)}";
}
--- /dev/null
+namespace Content.Server.StationEvents.Components;
+
+/// <summary>
+/// Gamerule component to mess up ai/borg laws when started.
+/// </summary>
+[RegisterComponent]
+public sealed partial class IonStormRuleComponent : Component
+{
+}
--- /dev/null
+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);
+ }
+}
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
/// <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";
}
--- /dev/null
+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);
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;
/// <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;
}
{
public EntityUid Entity = Entity;
- public readonly List<SiliconLaw> Laws = new();
+ public SiliconLawset Laws = new();
public bool Handled = false;
}
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
+using Robust.Shared.Prototypes;
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;
}
/// <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>
/// 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)
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>
/// <inheritdoc/>
[IdDataField]
public string ID { get; private set; } = default!;
-
-
}
--- /dev/null
+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();
+}
--- /dev/null
+- 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"
--- /dev/null
+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
--- /dev/null
+# 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
- type: SiliconLawBound
- type: EmagSiliconLaw
stunTime: 5
- emagLaws:
- - Syndicate1
- - Syndicate2
- - Syndicate3
- - Syndicate4
+ emagLaws: SyndicateStatic
+ - type: IonStormTarget
- type: Hands
showInHands: false
- type: IntrinsicRadioReceiver
#- type: GhostTakeoverAvailable
- type: SiliconLawBound
- type: SiliconLawProvider
- laws:
- - Drone1
- - Drone2
- - Drone3
+ laws: Drone
- type: MovementSpeedModifier
baseWalkSpeed : 5
baseSprintSpeed : 5
abstract: true
components:
- type: SiliconLawProvider
- laws:
- - Crewsimov1
- - Crewsimov2
- - Crewsimov3
+ laws: Crewsimov
- type: entity
id: BaseStationAllEventsEligible
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
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