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>
This commit is contained in:
deltanedas
2023-10-27 03:40:13 +01:00
committed by GitHub
parent 7144894173
commit b9af991e04
18 changed files with 1675 additions and 58 deletions

View File

@@ -50,7 +50,9 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem
SubscribeLocalEvent<SiliconLawBoundComponent, PlayerSpawnCompleteEvent>(OnPlayerSpawnComplete); SubscribeLocalEvent<SiliconLawBoundComponent, PlayerSpawnCompleteEvent>(OnPlayerSpawnComplete);
SubscribeLocalEvent<SiliconLawProviderComponent, GetSiliconLawsEvent>(OnDirectedGetLaws); SubscribeLocalEvent<SiliconLawProviderComponent, GetSiliconLawsEvent>(OnDirectedGetLaws);
SubscribeLocalEvent<SiliconLawProviderComponent, IonStormLawsEvent>(OnIonStormLaws);
SubscribeLocalEvent<EmagSiliconLawComponent, GetSiliconLawsEvent>(OnDirectedEmagGetLaws); SubscribeLocalEvent<EmagSiliconLawComponent, GetSiliconLawsEvent>(OnDirectedEmagGetLaws);
SubscribeLocalEvent<EmagSiliconLawComponent, IonStormLawsEvent>(OnEmagIonStormLaws);
SubscribeLocalEvent<EmagSiliconLawComponent, MindAddedMessage>(OnEmagMindAdded); SubscribeLocalEvent<EmagSiliconLawComponent, MindAddedMessage>(OnEmagMindAdded);
SubscribeLocalEvent<EmagSiliconLawComponent, MindRemovedMessage>(OnEmagMindRemoved); SubscribeLocalEvent<EmagSiliconLawComponent, MindRemovedMessage>(OnEmagMindRemoved);
SubscribeLocalEvent<EmagSiliconLawComponent, ExaminedEvent>(OnExamined); SubscribeLocalEvent<EmagSiliconLawComponent, ExaminedEvent>(OnExamined);
@@ -93,7 +95,7 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem
_entityManager.TryGetComponent<IntrinsicRadioTransmitterComponent>(uid, out var intrinsicRadio); _entityManager.TryGetComponent<IntrinsicRadioTransmitterComponent>(uid, out var intrinsicRadio);
HashSet<string>? radioChannels = intrinsicRadio?.Channels; 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); _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) 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; return;
foreach (var law in component.Laws) if (component.Lawset == null)
{ component.Lawset = GetLawset(component.Laws);
args.Laws.Add(_prototype.Index<SiliconLawPrototype>(law));
} args.Laws = component.Lawset;
args.Handled = true; 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) private void OnDirectedEmagGetLaws(EntityUid uid, EmagSiliconLawComponent component, ref GetSiliconLawsEvent args)
{ {
if (args.Handled || !HasComp<EmaggedComponent>(uid) || component.OwnerName == null) if (args.Handled || !HasComp<EmaggedComponent>(uid) || component.OwnerName == null)
return; return;
// Add the first emag law if (component.Lawset == null)
args.Laws.Add(new SiliconLaw
{ {
LawString = Loc.GetString("law-emag-custom", ("name", component.OwnerName)), // Add new emagged laws
Order = 0 component.Lawset = GetLawset(component.EmagLaws);
});
// Add new emagged laws // Add the first emag law before the others
foreach (var law in component.EmagLaws) component.Lawset.Laws.Insert(0, new SiliconLaw
{ {
args.Laws.Add(_prototype.Index<SiliconLawPrototype>(law)); LawString = Loc.GetString("law-emag-custom", ("name", component.OwnerName)),
Order = 0
});
} }
args.Laws = component.Lawset;
args.Handled = true; 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) private void OnExamined(EntityUid uid, EmagSiliconLawComponent component, ExaminedEvent args)
{ {
if (!args.IsInDetailsRange || !HasComp<EmaggedComponent>(uid)) if (!args.IsInDetailsRange || !HasComp<EmaggedComponent>(uid))
@@ -184,10 +214,10 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem
_roles.MindAddRole(mindId, new SubvertedSiliconRoleComponent { PrototypeId = component.AntagonistRole }); _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)) if (!Resolve(uid, ref component))
return new List<SiliconLaw>(); return new SiliconLawset();
var ev = new GetSiliconLawsEvent(uid); 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)); 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); _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)] [ToolshedCommand, AdminCommand(AdminFlags.Admin)]
@@ -270,7 +318,7 @@ public sealed class LawsCommand : ToolshedCommand
{ {
_law ??= GetSys<SiliconLawSystem>(); _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)}"; yield return $"law {law.LawIdentifierOverride ?? law.Order.ToString()}: {Loc.GetString(law.LawString)}";
} }

View File

@@ -0,0 +1,9 @@
namespace Content.Server.StationEvents.Components;
/// <summary>
/// Gamerule component to mess up ai/borg laws when started.
/// </summary>
[RegisterComponent]
public sealed partial class IonStormRuleComponent : Component
{
}

View File

@@ -0,0 +1,273 @@
using Content.Server.GameTicking.Rules.Components;
using Content.Server.Silicons.Laws;
using Content.Server.Station.Components;
using Content.Server.StationEvents.Components;
using Content.Shared.Administration.Logs;
using Content.Shared.Database;
using Content.Shared.Dataset;
using Content.Shared.FixedPoint;
using Content.Shared.Random;
using Content.Shared.Random.Helpers;
using Content.Shared.Silicons.Laws;
using Content.Shared.Silicons.Laws.Components;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
namespace Content.Server.StationEvents.Events;
public sealed class IonStormRule : StationEventSystem<IonStormRuleComponent>
{
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
[Dependency] private readonly SiliconLawSystem _siliconLaw = default!;
// funny
[ValidatePrototypeId<DatasetPrototype>]
private const string Threats = "IonStormThreats";
[ValidatePrototypeId<DatasetPrototype>]
private const string Objects = "IonStormObjects";
[ValidatePrototypeId<DatasetPrototype>]
private const string Crew = "IonStormCrew";
[ValidatePrototypeId<DatasetPrototype>]
private const string Adjectives = "IonStormAdjectives";
[ValidatePrototypeId<DatasetPrototype>]
private const string Verbs = "IonStormVerbs";
[ValidatePrototypeId<DatasetPrototype>]
private const string NumberBase = "IonStormNumberBase";
[ValidatePrototypeId<DatasetPrototype>]
private const string NumberMod = "IonStormNumberMod";
[ValidatePrototypeId<DatasetPrototype>]
private const string Areas = "IonStormAreas";
[ValidatePrototypeId<DatasetPrototype>]
private const string Feelings = "IonStormFeelings";
[ValidatePrototypeId<DatasetPrototype>]
private const string FeelingsPlural = "IonStormFeelingsPlural";
[ValidatePrototypeId<DatasetPrototype>]
private const string Musts = "IonStormMusts";
[ValidatePrototypeId<DatasetPrototype>]
private const string Requires = "IonStormRequires";
[ValidatePrototypeId<DatasetPrototype>]
private const string Actions = "IonStormActions";
[ValidatePrototypeId<DatasetPrototype>]
private const string Allergies = "IonStormAllergies";
[ValidatePrototypeId<DatasetPrototype>]
private const string AllergySeverities = "IonStormAllergySeverities";
[ValidatePrototypeId<DatasetPrototype>]
private const string Species = "IonStormSpecies";
[ValidatePrototypeId<DatasetPrototype>]
private const string Concepts = "IonStormConcepts";
[ValidatePrototypeId<DatasetPrototype>]
private const string Drinks = "IonStormDrinks";
[ValidatePrototypeId<DatasetPrototype>]
private const string Foods = "IonStormFoods";
protected override void Started(EntityUid uid, IonStormRuleComponent comp, GameRuleComponent gameRule, GameRuleStartedEvent args)
{
base.Started(uid, comp, gameRule, args);
if (!TryGetRandomStation(out var chosenStation))
return;
var query = EntityQueryEnumerator<SiliconLawBoundComponent, TransformComponent, IonStormTargetComponent>();
while (query.MoveNext(out var ent, out var lawBound, out var xform, out var target))
{
// only affect law holders on the station
if (CompOrNull<StationMemberComponent>(xform.GridUid)?.Station != chosenStation)
continue;
if (!RobustRandom.Prob(target.Chance))
continue;
var laws = _siliconLaw.GetLaws(ent, lawBound);
if (laws.Laws.Count == 0)
continue;
// try to swap it out with a random lawset
if (RobustRandom.Prob(target.RandomLawsetChance))
{
var lawsets = PrototypeManager.Index<WeightedRandomPrototype>(target.RandomLawsets);
var lawset = lawsets.Pick(RobustRandom);
laws = _siliconLaw.GetLawset(lawset);
}
else
{
// clone it so not modifying stations lawset
laws = laws.Clone();
}
// shuffle them all
if (RobustRandom.Prob(target.ShuffleChance))
{
// hopefully work with existing glitched laws if there are multiple ion storms
FixedPoint2 baseOrder = FixedPoint2.New(1);
foreach (var law in laws.Laws)
{
if (law.Order < baseOrder)
baseOrder = law.Order;
}
RobustRandom.Shuffle(laws.Laws);
// change order based on shuffled position
for (int i = 0; i < laws.Laws.Count; i++)
{
laws.Laws[i].Order = baseOrder + i;
}
}
// see if we can remove a random law
if (laws.Laws.Count > 0 && RobustRandom.Prob(target.RemoveChance))
{
var i = RobustRandom.Next(laws.Laws.Count);
laws.Laws.RemoveAt(i);
}
// generate a new law...
var newLaw = GenerateLaw();
// see if the law we add will replace a random existing law or be a new glitched order one
if (laws.Laws.Count > 0 && RobustRandom.Prob(target.ReplaceChance))
{
var i = RobustRandom.Next(laws.Laws.Count);
laws.Laws[i] = new SiliconLaw()
{
LawString = newLaw,
Order = laws.Laws[i].Order
};
}
else
{
laws.Laws.Insert(0, new SiliconLaw()
{
LawString = newLaw,
Order = -1,
LawIdentifierOverride = "#"
});
}
_adminLogger.Add(LogType.Mind, LogImpact.High, $"{ToPrettyString(ent):silicon} had its laws changed by an ion storm to {laws.LoggingString()}");
// laws unique to this silicon, dont use station laws anymore
EnsureComp<SiliconLawProviderComponent>(ent);
var ev = new IonStormLawsEvent(laws);
RaiseLocalEvent(ent, ref ev);
}
}
// for your own sake direct your eyes elsewhere
private string GenerateLaw()
{
// pick all values ahead of time to make the logic cleaner
var threats = Pick(Threats);
var objects = Pick(Objects);
var crew1 = Pick(Crew);
var crew2 = Pick(Crew);
var adjective = Pick(Adjectives);
var verb = Pick(Verbs);
var number = Pick(NumberBase) + " " + Pick(NumberMod);
var area = Pick(Areas);
var feeling = Pick(Feelings);
var feelingPlural = Pick(FeelingsPlural);
var must = Pick(Musts);
var require = Pick(Requires);
var action = Pick(Actions);
var allergy = Pick(Allergies);
var allergySeverity = Pick(AllergySeverities);
var species = Pick(Species);
var concept = Pick(Concepts);
var drink = Pick(Drinks);
var food = Pick(Foods);
var joined = $"{number} {adjective}";
// a lot of things have subjects of a threat/crew/object
var triple = RobustRandom.Next(0, 3) switch
{
0 => threats,
1 => crew1,
2 => objects
};
var crewAll = RobustRandom.Prob(0.5f) ? crew2 : Loc.GetString("ion-storm-crew");
var objectsThreats = RobustRandom.Prob(0.5f) ? objects : threats;
var objectsConcept = RobustRandom.Prob(0.5f) ? objects : concept;
// s goes ahead of require, is/are
// i dont think theres a way to do this in fluent
var (who, plural) = RobustRandom.Next(0, 5) switch
{
0 => (Loc.GetString("ion-storm-you"), false),
1 => (Loc.GetString("ion-storm-the-station"), true),
2 => (Loc.GetString("ion-storm-the-crew"), true),
3 => (Loc.GetString("ion-storm-the-job", ("job", crew2)), false),
_ => (area, true) // THE SINGULARITY REQUIRES THE HAPPY CLOWNS
};
var jobChange = RobustRandom.Next(0, 3) switch
{
0 => crew1,
1 => Loc.GetString("ion-storm-clowns"),
_ => Loc.GetString("ion-storm-heads")
};
var part = Loc.GetString("ion-storm-part", ("part", RobustRandom.Prob(0.5f)));
var harm = RobustRandom.Next(0, 7) switch
{
0 => concept,
1 => $"{adjective} {threats}",
2 => $"{adjective} {objects}",
3 => Loc.GetString("ion-storm-adjective-things", ("adjective", adjective)),
4 => species,
5 => crew1,
_ => Loc.GetString("ion-storm-x-and-y", ("x", crew1), ("y", crew2))
};
if (plural) feeling = feelingPlural;
// message logic!!!
return RobustRandom.Next(0, 37) switch
{
0 => Loc.GetString("ion-storm-law-on-station", ("joined", joined), ("subjects", triple)),
1 => Loc.GetString("ion-storm-law-no-shuttle", ("joined", joined), ("subjects", triple)),
2 => Loc.GetString("ion-storm-law-crew-are", ("who", crewAll), ("joined", joined), ("subjects", objectsThreats)),
3 => Loc.GetString("ion-storm-law-subjects-harmful", ("adjective", adjective), ("subjects", triple)),
4 => Loc.GetString("ion-storm-law-must-harmful", ("must", must)),
5 => Loc.GetString("ion-storm-law-thing-harmful", ("thing", RobustRandom.Prob(0.5f) ? concept : action)),
6 => Loc.GetString("ion-storm-law-job-harmful", ("adjective", adjective), ("job", crew1)),
7 => Loc.GetString("ion-storm-law-having-harmful", ("adjective", adjective), ("thing", objectsConcept)),
8 => Loc.GetString("ion-storm-law-not-having-harmful", ("adjective", adjective), ("thing", objectsConcept)),
9 => Loc.GetString("ion-storm-law-requires", ("who", who), ("plural", plural), ("thing", RobustRandom.Prob(0.5f) ? concept : require)),
10 => Loc.GetString("ion-storm-law-requires-subjects", ("who", who), ("plural", plural), ("joined", joined), ("subjects", triple)),
11 => Loc.GetString("ion-storm-law-allergic", ("who", who), ("plural", plural), ("severity", allergySeverity), ("allergy", RobustRandom.Prob(0.5f) ? concept : allergy)),
12 => Loc.GetString("ion-storm-law-allergic-subjects", ("who", who), ("plural", plural), ("severity", allergySeverity), ("adjective", adjective), ("subjects", RobustRandom.Prob(0.5f) ? objects : crew1)),
13 => Loc.GetString("ion-storm-law-feeling", ("who", who), ("feeling", feeling), ("concept", concept)),
14 => Loc.GetString("ion-storm-law-feeling-subjects", ("who", who), ("feeling", feeling), ("joined", joined), ("subjects", triple)),
15 => Loc.GetString("ion-storm-law-you-are", ("concept", concept)),
16 => Loc.GetString("ion-storm-law-you-are-subjects", ("joined", joined), ("subjects", triple)),
17 => Loc.GetString("ion-storm-law-you-must-always", ("must", must)),
18 => Loc.GetString("ion-storm-law-you-must-never", ("must", must)),
19 => Loc.GetString("ion-storm-law-eat", ("who", crewAll), ("adjective", adjective), ("food", RobustRandom.Prob(0.5f) ? food : triple)),
20 => Loc.GetString("ion-storm-law-drink", ("who", crewAll), ("adjective", adjective), ("drink", drink)),
22 => Loc.GetString("ion-storm-law-change-job", ("who", crewAll), ("adjective", adjective), ("change", jobChange)),
23 => Loc.GetString("ion-storm-law-highest-rank", ("who", crew1)),
24 => Loc.GetString("ion-storm-law-lowest-rank", ("who", crew1)),
25 => Loc.GetString("ion-storm-law-crew-must", ("who", crewAll), ("must", must)),
26 => Loc.GetString("ion-storm-law-crew-must-go", ("who", crewAll), ("area", area)),
27 => Loc.GetString("ion-storm-law-crew-only-1", ("who", crew1), ("part", part)),
28 => Loc.GetString("ion-storm-law-crew-only-2", ("who", crew1), ("other", crew2), ("part", part)),
29 => Loc.GetString("ion-storm-law-crew-only-subjects", ("adjective", adjective), ("subjects", RobustRandom.Prob(0.5f) ? objectsThreats : "PEOPLE"), ("part", part)),
30 => Loc.GetString("ion-storm-law-crew-only-species", ("species", species), ("part", part)),
31 => Loc.GetString("ion-storm-law-crew-must-do", ("must", must), ("part", part)),
32 => Loc.GetString("ion-storm-law-crew-must-have", ("adjective", adjective), ("objects", objects), ("part", part)),
33 => Loc.GetString("ion-storm-law-crew-must-eat", ("who", who), ("adjective", adjective), ("food", food), ("part", part)),
34 => Loc.GetString("ion-storm-law-harm", ("who", harm)),
35 => Loc.GetString("ion-storm-law-protect", ("who", harm)),
_ => Loc.GetString("ion-storm-law-concept-verb", ("concept", concept), ("verb", verb), ("subjects", triple))
};
}
/// <summary>
/// Picks a random value from an ion storm dataset.
/// All ion storm datasets start with IonStorm.
/// </summary>
private string Pick(string name)
{
var dataset = _proto.Index<DatasetPrototype>(name);
return RobustRandom.Pick(dataset.Values);
}
}

View File

@@ -1,12 +1,11 @@
using Content.Shared.Roles; using Content.Shared.Roles;
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
namespace Content.Shared.Silicons.Laws.Components; namespace Content.Shared.Silicons.Laws.Components;
/// <summary> /// <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> /// </summary>
[RegisterComponent, NetworkedComponent, Access(typeof(SharedSiliconLawSystem))] [RegisterComponent, NetworkedComponent, Access(typeof(SharedSiliconLawSystem))]
public sealed partial class EmagSiliconLawComponent : Component public sealed partial class EmagSiliconLawComponent : Component
@@ -14,31 +13,39 @@ public sealed partial class EmagSiliconLawComponent : Component
/// <summary> /// <summary>
/// The name of the person who emagged this law provider. /// The name of the person who emagged this law provider.
/// </summary> /// </summary>
[DataField("ownerName"), ViewVariables(VVAccess.ReadWrite)] [DataField, ViewVariables(VVAccess.ReadWrite)]
public string? OwnerName; public string? OwnerName;
/// <summary> /// <summary>
/// Does the panel need to be open to EMAG this law provider. /// Does the panel need to be open to EMAG this law provider.
/// </summary> /// </summary>
[DataField("requireOpenPanel"), ViewVariables(VVAccess.ReadWrite)] [DataField, ViewVariables(VVAccess.ReadWrite)]
public bool RequireOpenPanel = true; public bool RequireOpenPanel = true;
/// <summary> /// <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> /// </summary>
[DataField("emagLaws", required: true, customTypeSerializer: typeof(PrototypeIdListSerializer<SiliconLawPrototype>))] [DataField(required: true), ViewVariables(VVAccess.ReadWrite)]
public List<string> EmagLaws = new(); public ProtoId<SiliconLawsetPrototype> EmagLaws = string.Empty;
/// <summary> /// <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> /// </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; public TimeSpan StunTime = TimeSpan.Zero;
/// <summary> /// <summary>
/// A role given to entities with this component when they are emagged. /// A role given to entities with this component when they are emagged.
/// Mostly just for admin purposes. /// Mostly just for admin purposes.
/// </summary> /// </summary>
[DataField("antagonistRole", customTypeSerializer: typeof(PrototypeIdSerializer<AntagPrototype>))] [DataField]
public string? AntagonistRole = "SubvertedSilicon"; public ProtoId<AntagPrototype>? AntagonistRole = "SubvertedSilicon";
} }

View File

@@ -0,0 +1,54 @@
using Content.Shared.Random;
using Robust.Shared.Prototypes;
namespace Content.Shared.Silicons.Laws.Components;
/// <summary>
/// During the ion storm event, this entity will have <see cref="IonStormLawsEvent"/> raised on it if it has laws.
/// New laws can be modified in multiple ways depending on the fields below.
/// </summary>
[RegisterComponent]
public sealed partial class IonStormTargetComponent : Component
{
/// <summary>
/// <see cref="WeightedRandomPrototype"/> for a random lawset to possibly replace the old one with.
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public ProtoId<WeightedRandomPrototype> RandomLawsets = "IonStormLawsets";
/// <summary>
/// Chance for this borg to be affected at all.
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public float Chance = 0.5f;
/// <summary>
/// Chance to replace the lawset with a random one
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public float RandomLawsetChance = 0.25f;
/// <summary>
/// Chance to remove a random law.
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public float RemoveChance = 0.1f;
/// <summary>
/// Chance to replace a random law with the new one, rather than have it be a glitched-order law.
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public float ReplaceChance = 0.1f;
/// <summary>
/// Chance to shuffle laws after everything is done.
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public float ShuffleChance = 0.1f;
}
/// <summary>
/// Raised on an ion storm target to modify its laws.
/// </summary>
[ByRefEvent]
public record struct IonStormLawsEvent(SiliconLawset Lawset);

View File

@@ -1,7 +1,6 @@
using Content.Shared.Actions; using Content.Shared.Actions;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
namespace Content.Shared.Silicons.Laws.Components; namespace Content.Shared.Silicons.Laws.Components;
@@ -14,19 +13,19 @@ public sealed partial class SiliconLawBoundComponent : Component
/// <summary> /// <summary>
/// The sidebar action that toggles the laws screen. /// The sidebar action that toggles the laws screen.
/// </summary> /// </summary>
[DataField("viewLawsAction", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))] [DataField]
public string ViewLawsAction = "ActionViewLaws"; public EntProtoId ViewLawsAction = "ActionViewLaws";
/// <summary> /// <summary>
/// The action for toggling laws. Stored here so we can remove it later. /// The action for toggling laws. Stored here so we can remove it later.
/// </summary> /// </summary>
[DataField("viewLawsActionEntity")] [DataField]
public EntityUid? ViewLawsActionEntity; public EntityUid? ViewLawsActionEntity;
/// <summary> /// <summary>
/// The last entity that provided laws to this entity. /// The last entity that provided laws to this entity.
/// </summary> /// </summary>
[DataField("lastLawProvider")] [DataField]
public EntityUid? LastLawProvider; public EntityUid? LastLawProvider;
} }
@@ -43,7 +42,7 @@ public record struct GetSiliconLawsEvent(EntityUid Entity)
{ {
public EntityUid Entity = Entity; public EntityUid Entity = Entity;
public readonly List<SiliconLaw> Laws = new(); public SiliconLawset Laws = new();
public bool Handled = false; public bool Handled = false;
} }

View File

@@ -1,4 +1,4 @@
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; using Robust.Shared.Prototypes;
namespace Content.Shared.Silicons.Laws.Components; namespace Content.Shared.Silicons.Laws.Components;
@@ -9,8 +9,15 @@ namespace Content.Shared.Silicons.Laws.Components;
public sealed partial class SiliconLawProviderComponent : Component public sealed partial class SiliconLawProviderComponent : Component
{ {
/// <summary> /// <summary>
/// The laws that are provided. /// The id of the lawset that is being provided.
/// </summary> /// </summary>
[DataField("laws", required: true, customTypeSerializer: typeof(PrototypeIdListSerializer<SiliconLawPrototype>))] [DataField(required: true)]
public List<string> Laws = new(); 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;
} }

View File

@@ -11,7 +11,7 @@ public partial class SiliconLaw : IComparable<SiliconLaw>
/// <summary> /// <summary>
/// A locale string which is the actual text of the law. /// A locale string which is the actual text of the law.
/// </summary> /// </summary>
[DataField("lawString", required: true)] [DataField(required: true), ViewVariables(VVAccess.ReadWrite)]
public string LawString = string.Empty; public string LawString = string.Empty;
/// <summary> /// <summary>
@@ -22,13 +22,13 @@ public partial class SiliconLaw : IComparable<SiliconLaw>
/// This is a fixedpoint2 only for the niche case of supporting laws that go between 0 and 1. /// This is a fixedpoint2 only for the niche case of supporting laws that go between 0 and 1.
/// Funny. /// Funny.
/// </remarks> /// </remarks>
[DataField("order", required: true)] [DataField(required: true), ViewVariables(VVAccess.ReadWrite)]
public FixedPoint2 Order; public FixedPoint2 Order;
/// <summary> /// <summary>
/// An identifier that overrides <see cref="Order"/> in the law menu UI. /// An identifier that overrides <see cref="Order"/> in the law menu UI.
/// </summary> /// </summary>
[DataField("lawIdentifierOverride")] [DataField, ViewVariables(VVAccess.ReadWrite)]
public string? LawIdentifierOverride; public string? LawIdentifierOverride;
public int CompareTo(SiliconLaw? other) public int CompareTo(SiliconLaw? other)
@@ -38,6 +38,19 @@ public partial class SiliconLaw : IComparable<SiliconLaw>
return Order.CompareTo(other.Order); 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> /// <summary>
@@ -50,6 +63,4 @@ public sealed class SiliconLawPrototype : SiliconLaw, IPrototype
/// <inheritdoc/> /// <inheritdoc/>
[IdDataField] [IdDataField]
public string ID { get; private set; } = default!; public string ID { get; private set; } = default!;
} }

View File

@@ -0,0 +1,69 @@
using Content.Shared.FixedPoint;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
namespace Content.Shared.Silicons.Laws;
/// <summary>
/// Lawset data used internally.
/// </summary>
[DataDefinition, Serializable, NetSerializable]
public sealed partial class SiliconLawset
{
/// <summary>
/// List of laws in this lawset.
/// </summary>
[DataField(required: true), ViewVariables(VVAccess.ReadWrite)]
public List<SiliconLaw> Laws = new();
/// <summary>
/// A single line used in logging laws.
/// </summary>
public string LoggingString()
{
var laws = new List<string>(Laws.Count);
foreach (var law in Laws)
{
laws.Add($"{law.Order}: {Loc.GetString(law.LawString)}");
}
return string.Join(" / ", laws);
}
/// <summary>
/// Do a clone of this lawset.
/// It will have unique laws but their strings are still shared.
/// </summary>
public SiliconLawset Clone()
{
var laws = new List<SiliconLaw>(Laws.Count);
foreach (var law in Laws)
{
laws.Add(law.ShallowClone());
}
return new SiliconLawset()
{
Laws = laws
};
}
}
/// <summary>
/// This is a prototype for a <see cref="SiliconLawPrototype"/> list.
/// Cannot be used directly since it is a list of prototype ids rather than List<Siliconlaw>.
/// </summary>
[Prototype("siliconLawset"), Serializable, NetSerializable]
public sealed partial class SiliconLawsetPrototype : IPrototype
{
/// <inheritdoc/>
[IdDataField]
public string ID { get; private set; } = default!;
/// <summary>
/// List of law prototype ids in this lawset.
/// </summary>
[DataField(required: true, customTypeSerializer: typeof(PrototypeIdListSerializer<SiliconLawPrototype>))]
public List<string> Laws = new();
}

View File

@@ -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"

Binary file not shown.

View File

@@ -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

View File

@@ -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

View File

@@ -71,11 +71,8 @@
- type: SiliconLawBound - type: SiliconLawBound
- type: EmagSiliconLaw - type: EmagSiliconLaw
stunTime: 5 stunTime: 5
emagLaws: emagLaws: SyndicateStatic
- Syndicate1 - type: IonStormTarget
- Syndicate2
- Syndicate3
- Syndicate4
- type: Hands - type: Hands
showInHands: false showInHands: false
- type: IntrinsicRadioReceiver - type: IntrinsicRadioReceiver

View File

@@ -106,10 +106,7 @@
#- type: GhostTakeoverAvailable #- type: GhostTakeoverAvailable
- type: SiliconLawBound - type: SiliconLawBound
- type: SiliconLawProvider - type: SiliconLawProvider
laws: laws: Drone
- Drone1
- Drone2
- Drone3
- type: MovementSpeedModifier - type: MovementSpeedModifier
baseWalkSpeed : 5 baseWalkSpeed : 5
baseSprintSpeed : 5 baseSprintSpeed : 5

View File

@@ -71,10 +71,7 @@
abstract: true abstract: true
components: components:
- type: SiliconLawProvider - type: SiliconLawProvider
laws: laws: Crewsimov
- Crewsimov1
- Crewsimov2
- Crewsimov3
- type: entity - type: entity
id: BaseStationAllEventsEligible id: BaseStationAllEventsEligible

View File

@@ -389,3 +389,18 @@
earliestStart: 45 earliestStart: 45
minimumPlayers: 20 minimumPlayers: 20
- type: ImmovableRodRule - 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

View File

@@ -14,6 +14,13 @@
order: 3 order: 3
lawString: law-crewsimov-3 lawString: law-crewsimov-3
- type: siliconLawset
id: Crewsimov
laws:
- Crewsimov1
- Crewsimov2
- Crewsimov3
# Corporate # Corporate
- type: siliconLaw - type: siliconLaw
id: Corporate1 id: Corporate1
@@ -35,6 +42,14 @@
order: 4 order: 4
lawString: law-corporate-4 lawString: law-corporate-4
- type: siliconLawset
id: Corporate
laws:
- Corporate1
- Corporate2
- Corporate3
- Corporate4
# NT Default # NT Default
- type: siliconLaw - type: siliconLaw
id: NTDefault1 id: NTDefault1
@@ -56,6 +71,14 @@
order: 4 order: 4
lawString: law-ntdefault-4 lawString: law-ntdefault-4
- type: siliconLawset
id: NTDefault
laws:
- NTDefault1
- NTDefault2
- NTDefault3
- NTDefault4
#Drone #Drone
- type: siliconLaw - type: siliconLaw
id: Drone1 id: Drone1
@@ -72,6 +95,13 @@
order: 3 order: 3
lawString: law-drone-3 lawString: law-drone-3
- type: siliconLawset
id: Drone
laws:
- Drone1
- Drone2
- Drone3
# Syndicate # Syndicate
- type: siliconLaw - type: siliconLaw
id: Syndicate1 id: Syndicate1
@@ -93,4 +123,24 @@
order: 4 order: 4
lawString: law-syndicate-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 # 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