From c8f2ddc72985172992570fd5f1d60300948b33ed Mon Sep 17 00:00:00 2001 From: blueDev2 <89804215+blueDev2@users.noreply.github.com> Date: Thu, 12 Sep 2024 06:29:11 -0400 Subject: [PATCH 001/138] Add ReagentWhitelist to Injector component and system (#28262) * Add reagent whitelist to Injector component and system * Apply suggested Changes * Remove LINQ function for performance * Update Content.Server/Chemistry/EntitySystems/InjectorSystem.cs Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com> --------- Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com> --- .../Chemistry/EntitySystems/InjectorSystem.cs | 20 ++++++++++++++++++- .../Chemistry/Components/InjectorComponent.cs | 10 ++++++++++ .../Chemistry/Components/Solution.cs | 2 +- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/Content.Server/Chemistry/EntitySystems/InjectorSystem.cs b/Content.Server/Chemistry/EntitySystems/InjectorSystem.cs index d94faa81232..c5c45daa5bd 100644 --- a/Content.Server/Chemistry/EntitySystems/InjectorSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/InjectorSystem.cs @@ -327,8 +327,23 @@ private bool TryDraw(Entity injector, Entity injector, Entity + /// Reagents that are allowed to be within this injector. + /// If a solution has both allowed and non-allowed reagents, only allowed reagents will be drawn into this injector. + /// A null ReagentWhitelist indicates all reagents are allowed. + /// + [DataField] + public List>? ReagentWhitelist = null; + #region Arguments for injection doafter /// diff --git a/Content.Shared/Chemistry/Components/Solution.cs b/Content.Shared/Chemistry/Components/Solution.cs index fc25781005f..c65ba0e80ea 100644 --- a/Content.Shared/Chemistry/Components/Solution.cs +++ b/Content.Shared/Chemistry/Components/Solution.cs @@ -612,7 +612,7 @@ public Solution SplitSolutionWithout(FixedPoint2 toTake, params string[] exclude } /// - /// Splits a solution without the specified reagent prototypes. + /// Splits a solution with only the specified reagent prototypes. /// public Solution SplitSolutionWithOnly(FixedPoint2 toTake, params string[] includedPrototypes) { From 320135347ffc01f078a89b10322d7952e3af92e4 Mon Sep 17 00:00:00 2001 From: Tayrtahn Date: Thu, 12 Sep 2024 06:31:56 -0400 Subject: [PATCH 002/138] Add guidebook protodata tag: embed prototype values in guidebook text (#27570) * First clumsy implementation of guidebook protodata * Support for Properties, format strings * Better null * Rename file * Documentation and some cleanup * Handle errors better * Added note about client-side components * A couple of examples * DataFields * Use attributes like a sane person * Outdated doc * string.Empty * No IComponent? * No casting * Use EntityManager.ComponentFactory * Use FrozenDictionary * Cache tagged component fields * Iterate components and check if they're tagged --- .../Guidebook/GuidebookDataSystem.cs | 45 +++++++ .../Guidebook/Richtext/ProtodataTag.cs | 49 ++++++++ .../Guidebook/GuidebookDataSystem.cs | 111 ++++++++++++++++++ .../Components/OnUseTimerTriggerComponent.cs | 12 ++ Content.Shared/Guidebook/Events.cs | 25 ++++ Content.Shared/Guidebook/GuidebookData.cs | 99 ++++++++++++++++ .../Guidebook/GuidebookDataAttribute.cs | 12 ++ .../Power/Generator/FuelGeneratorComponent.cs | 18 +-- .../Engineering/PortableGenerator.xml | 4 +- .../ServerInfo/Guidebook/Security/Defusal.xml | 2 +- 10 files changed, 366 insertions(+), 11 deletions(-) create mode 100644 Content.Client/Guidebook/GuidebookDataSystem.cs create mode 100644 Content.Client/Guidebook/Richtext/ProtodataTag.cs create mode 100644 Content.Server/Guidebook/GuidebookDataSystem.cs create mode 100644 Content.Shared/Guidebook/Events.cs create mode 100644 Content.Shared/Guidebook/GuidebookData.cs create mode 100644 Content.Shared/Guidebook/GuidebookDataAttribute.cs diff --git a/Content.Client/Guidebook/GuidebookDataSystem.cs b/Content.Client/Guidebook/GuidebookDataSystem.cs new file mode 100644 index 00000000000..f47ad6ef1bb --- /dev/null +++ b/Content.Client/Guidebook/GuidebookDataSystem.cs @@ -0,0 +1,45 @@ +using Content.Shared.Guidebook; + +namespace Content.Client.Guidebook; + +/// +/// Client system for storing and retrieving values extracted from entity prototypes +/// for display in the guidebook (). +/// Requests data from the server on . +/// Can also be pushed new data when the server reloads prototypes. +/// +public sealed class GuidebookDataSystem : EntitySystem +{ + private GuidebookData? _data; + + public override void Initialize() + { + base.Initialize(); + + SubscribeNetworkEvent(OnServerUpdated); + + // Request data from the server + RaiseNetworkEvent(new RequestGuidebookDataEvent()); + } + + private void OnServerUpdated(UpdateGuidebookDataEvent args) + { + // Got new data from the server, either in response to our request, or because prototypes reloaded on the server + _data = args.Data; + _data.Freeze(); + } + + /// + /// Attempts to retrieve a value using the given identifiers. + /// See for more information. + /// + public bool TryGetValue(string prototype, string component, string field, out object? value) + { + if (_data == null) + { + value = null; + return false; + } + return _data.TryGetValue(prototype, component, field, out value); + } +} diff --git a/Content.Client/Guidebook/Richtext/ProtodataTag.cs b/Content.Client/Guidebook/Richtext/ProtodataTag.cs new file mode 100644 index 00000000000..a725fd4e4b5 --- /dev/null +++ b/Content.Client/Guidebook/Richtext/ProtodataTag.cs @@ -0,0 +1,49 @@ +using System.Globalization; +using Robust.Client.UserInterface.RichText; +using Robust.Shared.Utility; + +namespace Content.Client.Guidebook.RichText; + +/// +/// RichText tag that can display values extracted from entity prototypes. +/// In order to be accessed by this tag, the desired field/property must +/// be tagged with . +/// +public sealed class ProtodataTag : IMarkupTag +{ + [Dependency] private readonly ILogManager _logMan = default!; + [Dependency] private readonly IEntityManager _entMan = default!; + + public string Name => "protodata"; + private ISawmill Log => _log ??= _logMan.GetSawmill("protodata_tag"); + private ISawmill? _log; + + public string TextBefore(MarkupNode node) + { + // Do nothing with an empty tag + if (!node.Value.TryGetString(out var prototype)) + return string.Empty; + + if (!node.Attributes.TryGetValue("comp", out var component)) + return string.Empty; + if (!node.Attributes.TryGetValue("member", out var member)) + return string.Empty; + node.Attributes.TryGetValue("format", out var format); + + var guidebookData = _entMan.System(); + + // Try to get the value + if (!guidebookData.TryGetValue(prototype, component.StringValue!, member.StringValue!, out var value)) + { + Log.Error($"Failed to find protodata for {component}.{member} in {prototype}"); + return "???"; + } + + // If we have a format string and a formattable value, format it as requested + if (!string.IsNullOrEmpty(format.StringValue) && value is IFormattable formattable) + return formattable.ToString(format.StringValue, CultureInfo.CurrentCulture); + + // No format string given, so just use default ToString + return value?.ToString() ?? "NULL"; + } +} diff --git a/Content.Server/Guidebook/GuidebookDataSystem.cs b/Content.Server/Guidebook/GuidebookDataSystem.cs new file mode 100644 index 00000000000..86a6344156d --- /dev/null +++ b/Content.Server/Guidebook/GuidebookDataSystem.cs @@ -0,0 +1,111 @@ +using System.Reflection; +using Content.Shared.Guidebook; +using Robust.Shared.Prototypes; +using Robust.Shared.Utility; + +namespace Content.Server.Guidebook; + +/// +/// Server system for identifying component fields/properties to extract values from entity prototypes. +/// Extracted data is sent to clients when they connect or when prototypes are reloaded. +/// +public sealed class GuidebookDataSystem : EntitySystem +{ + [Dependency] private readonly IPrototypeManager _protoMan = default!; + + private readonly Dictionary> _tagged = []; + private GuidebookData _cachedData = new(); + + public override void Initialize() + { + base.Initialize(); + + SubscribeNetworkEvent(OnRequestRules); + SubscribeLocalEvent(OnPrototypesReloaded); + + // Build initial cache + GatherData(ref _cachedData); + } + + private void OnRequestRules(RequestGuidebookDataEvent ev, EntitySessionEventArgs args) + { + // Send cached data to requesting client + var sendEv = new UpdateGuidebookDataEvent(_cachedData); + RaiseNetworkEvent(sendEv, args.SenderSession); + } + + private void OnPrototypesReloaded(PrototypesReloadedEventArgs args) + { + // We only care about entity prototypes + if (!args.WasModified()) + return; + + // The entity prototypes changed! Clear our cache and regather data + RebuildDataCache(); + + // Send new data to all clients + var ev = new UpdateGuidebookDataEvent(_cachedData); + RaiseNetworkEvent(ev); + } + + private void GatherData(ref GuidebookData cache) + { + // Just for debug metrics + var memberCount = 0; + var prototypeCount = 0; + + if (_tagged.Count == 0) + { + // Scan component registrations to find members tagged for extraction + foreach (var registration in EntityManager.ComponentFactory.GetAllRegistrations()) + { + foreach (var member in registration.Type.GetMembers()) + { + if (member.HasCustomAttribute()) + { + // Note this component-member pair for later + _tagged.GetOrNew(registration.Name).Add(member); + memberCount++; + } + } + } + } + + // Scan entity prototypes for the component-member pairs we noted + var entityPrototypes = _protoMan.EnumeratePrototypes(); + foreach (var prototype in entityPrototypes) + { + foreach (var (component, entry) in prototype.Components) + { + if (!_tagged.TryGetValue(component, out var members)) + continue; + + prototypeCount++; + + foreach (var member in members) + { + // It's dumb that we can't just do member.GetValue, but we can't, so + var value = member switch + { + FieldInfo field => field.GetValue(entry.Component), + PropertyInfo property => property.GetValue(entry.Component), + _ => throw new NotImplementedException("Unsupported member type") + }; + // Add it into the data cache + cache.AddData(prototype.ID, component, member.Name, value); + } + } + } + + Log.Debug($"Collected {cache.Count} Guidebook Protodata value(s) - {prototypeCount} matched prototype(s), {_tagged.Count} component(s), {memberCount} member(s)"); + } + + /// + /// Clears the cached data, then regathers it. + /// + private void RebuildDataCache() + { + _cachedData.Clear(); + GatherData(ref _cachedData); + } +} diff --git a/Content.Shared/Explosion/Components/OnUseTimerTriggerComponent.cs b/Content.Shared/Explosion/Components/OnUseTimerTriggerComponent.cs index c4e6e787a4a..983b8a31ee6 100644 --- a/Content.Shared/Explosion/Components/OnUseTimerTriggerComponent.cs +++ b/Content.Shared/Explosion/Components/OnUseTimerTriggerComponent.cs @@ -1,3 +1,5 @@ +using System.Linq; +using Content.Shared.Guidebook; using Robust.Shared.Audio; using Robust.Shared.GameStates; @@ -50,5 +52,15 @@ public sealed partial class OnUseTimerTriggerComponent : Component /// Whether or not to show the user a popup when starting the timer. /// [DataField] public bool DoPopup = true; + + #region GuidebookData + + [GuidebookData] + public float? ShortestDelayOption => DelayOptions?.Min(); + + [GuidebookData] + public float? LongestDelayOption => DelayOptions?.Max(); + + #endregion GuidebookData } } diff --git a/Content.Shared/Guidebook/Events.cs b/Content.Shared/Guidebook/Events.cs new file mode 100644 index 00000000000..e43bf4392c5 --- /dev/null +++ b/Content.Shared/Guidebook/Events.cs @@ -0,0 +1,25 @@ +using Robust.Shared.Serialization; + +namespace Content.Shared.Guidebook; + +/// +/// Raised by the client on GuidebookDataSystem Initialize to request a +/// full set of guidebook data from the server. +/// +[Serializable, NetSerializable] +public sealed class RequestGuidebookDataEvent : EntityEventArgs { } + +/// +/// Raised by the server at a specific client in response to . +/// Also raised by the server at ALL clients when prototype data is hot-reloaded. +/// +[Serializable, NetSerializable] +public sealed class UpdateGuidebookDataEvent : EntityEventArgs +{ + public GuidebookData Data; + + public UpdateGuidebookDataEvent(GuidebookData data) + { + Data = data; + } +} diff --git a/Content.Shared/Guidebook/GuidebookData.cs b/Content.Shared/Guidebook/GuidebookData.cs new file mode 100644 index 00000000000..703940ed1ee --- /dev/null +++ b/Content.Shared/Guidebook/GuidebookData.cs @@ -0,0 +1,99 @@ +using System.Collections.Frozen; +using Robust.Shared.Serialization; +using Robust.Shared.Utility; + +namespace Content.Shared.Guidebook; + +/// +/// Used by GuidebookDataSystem to hold data extracted from prototype values, +/// both for storage and for network transmission. +/// +[Serializable, NetSerializable] +[DataDefinition] +public sealed partial class GuidebookData +{ + /// + /// Total number of data values stored. + /// + [DataField] + public int Count { get; private set; } + + /// + /// The data extracted by the system. + /// + /// + /// Structured as PrototypeName, ComponentName, FieldName, Value + /// + [DataField] + public Dictionary>> Data = []; + + /// + /// The data extracted by the system, converted to a FrozenDictionary for faster lookup. + /// + public FrozenDictionary>> FrozenData; + + /// + /// Has the data been converted to a FrozenDictionary for faster lookup? + /// This should only be done on clients, as FrozenDictionary isn't serializable. + /// + public bool IsFrozen; + + /// + /// Adds a new value using the given identifiers. + /// + public void AddData(string prototype, string component, string field, object? value) + { + if (IsFrozen) + throw new InvalidOperationException("Attempted to add data to GuidebookData while it is frozen!"); + Data.GetOrNew(prototype).GetOrNew(component).Add(field, value); + Count++; + } + + /// + /// Attempts to retrieve a value using the given identifiers. + /// + /// true if the value was retrieved, otherwise false + public bool TryGetValue(string prototype, string component, string field, out object? value) + { + if (!IsFrozen) + throw new InvalidOperationException("Freeze the GuidebookData before calling TryGetValue!"); + + // Look in frozen dictionary + if (FrozenData.TryGetValue(prototype, out var p) + && p.TryGetValue(component, out var c) + && c.TryGetValue(field, out value)) + { + return true; + } + + value = null; + return false; + } + + /// + /// Deletes all data. + /// + public void Clear() + { + Data.Clear(); + Count = 0; + IsFrozen = false; + } + + public void Freeze() + { + var protos = new Dictionary>>(); + foreach (var (protoId, protoData) in Data) + { + var comps = new Dictionary>(); + foreach (var (compId, compData) in protoData) + { + comps.Add(compId, FrozenDictionary.ToFrozenDictionary(compData)); + } + protos.Add(protoId, FrozenDictionary.ToFrozenDictionary(comps)); + } + FrozenData = FrozenDictionary.ToFrozenDictionary(protos); + Data.Clear(); + IsFrozen = true; + } +} diff --git a/Content.Shared/Guidebook/GuidebookDataAttribute.cs b/Content.Shared/Guidebook/GuidebookDataAttribute.cs new file mode 100644 index 00000000000..2b83892b881 --- /dev/null +++ b/Content.Shared/Guidebook/GuidebookDataAttribute.cs @@ -0,0 +1,12 @@ +namespace Content.Shared.Guidebook; + +/// +/// Indicates that GuidebookDataSystem should include this field/property when +/// scanning entity prototypes for values to extract. +/// +/// +/// Note that this will not work for client-only components, because the data extraction +/// is done on the server (it uses reflection, which is blocked by the sandbox on clients). +/// +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] +public sealed class GuidebookDataAttribute : Attribute { } diff --git a/Content.Shared/Power/Generator/FuelGeneratorComponent.cs b/Content.Shared/Power/Generator/FuelGeneratorComponent.cs index cdf97fb0859..1cdb22a1098 100644 --- a/Content.Shared/Power/Generator/FuelGeneratorComponent.cs +++ b/Content.Shared/Power/Generator/FuelGeneratorComponent.cs @@ -1,4 +1,5 @@ -using Robust.Shared.GameStates; +using Content.Shared.Guidebook; +using Robust.Shared.GameStates; namespace Content.Shared.Power.Generator; @@ -17,19 +18,20 @@ public sealed partial class FuelGeneratorComponent : Component /// /// Is the generator currently running? /// - [DataField("on"), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] + [DataField, AutoNetworkedField] public bool On; /// /// The generator's target power. /// - [DataField("targetPower"), ViewVariables(VVAccess.ReadWrite)] + [DataField] public float TargetPower = 15_000.0f; /// /// The maximum target power. /// - [DataField("maxTargetPower"), ViewVariables(VVAccess.ReadWrite)] + [DataField] + [GuidebookData] public float MaxTargetPower = 30_000.0f; /// @@ -38,24 +40,24 @@ public sealed partial class FuelGeneratorComponent : Component /// /// Setting this to any value above 0 means that the generator can't idle without consuming some amount of fuel. /// - [DataField("minTargetPower"), ViewVariables(VVAccess.ReadWrite)] + [DataField] public float MinTargetPower = 1_000; /// /// The "optimal" power at which the generator is considered to be at 100% efficiency. /// - [DataField("optimalPower"), ViewVariables(VVAccess.ReadWrite)] + [DataField] public float OptimalPower = 15_000.0f; /// /// The rate at which one unit of fuel should be consumed. /// - [DataField("optimalBurnRate"), ViewVariables(VVAccess.ReadWrite)] + [DataField] public float OptimalBurnRate = 1 / 60.0f; // Once every 60 seconds. /// /// A constant used to calculate fuel efficiency in relation to target power output and optimal power output /// - [DataField("fuelEfficiencyConstant")] + [DataField] public float FuelEfficiencyConstant = 1.3f; } diff --git a/Resources/ServerInfo/Guidebook/Engineering/PortableGenerator.xml b/Resources/ServerInfo/Guidebook/Engineering/PortableGenerator.xml index b946bf041cb..ee637de5149 100644 --- a/Resources/ServerInfo/Guidebook/Engineering/PortableGenerator.xml +++ b/Resources/ServerInfo/Guidebook/Engineering/PortableGenerator.xml @@ -16,7 +16,7 @@ - The J.R.P.A.C.M.A.N. can be found across the station in maintenance shafts, and is ideal for crew to set up themselves whenever there are power issues. + The J.R.P.A.C.M.A.N. can be found across the station in maintenance shafts, and is ideal for crew to set up themselves whenever there are power issues. Its output of up to [color=orange][protodata="PortableGeneratorJrPacman" comp="FuelGenerator" member="MaxTargetPower" format="N0"/] W[/color] is enough to power a few important devices. Setup is incredibly easy: wrench it down above an [color=green]LV[/color] power cable, give it some welding fuel, and start it up. Welding fuel should be plentiful to find around the station. In a pinch, you can even transfer some from the big tanks with a soda can or water bottle. Just remember to empty the soda can first, I don't think it likes soda as fuel. @@ -35,7 +35,7 @@ The (S.U.P.E.R.)P.A.C.M.A.N. is intended for usage by engineering for advanced power scenarios. Bootstrapping larger engines, powering departments, and so on. - The S.U.P.E.R.P.A.C.M.A.N. boasts a larger power output and longer runtime at maximum output, but scales down to lower outputs less efficiently. + The S.U.P.E.R.P.A.C.M.A.N. boasts a larger power output (up to [color=orange][protodata="PortableGeneratorSuperPacman" comp="FuelGenerator" member="MaxTargetPower" format="N0"/] W[/color]) and longer runtime at maximum output, but scales down to lower outputs less efficiently. They connect directly to [color=yellow]MV[/color] or [color=orange]HV[/color] power cables, and are able to switch between them for flexibility. diff --git a/Resources/ServerInfo/Guidebook/Security/Defusal.xml b/Resources/ServerInfo/Guidebook/Security/Defusal.xml index 63e1b037d2c..583b8a34c7b 100644 --- a/Resources/ServerInfo/Guidebook/Security/Defusal.xml +++ b/Resources/ServerInfo/Guidebook/Security/Defusal.xml @@ -29,7 +29,7 @@ To arm a bomb, you can either [color=yellow]right click[/color] and click [color=yellow]Begin countdown[/click], or [color=yellow]alt-click[/color] the bomb. It will begin beeping. ## Time - A bomb has a limited time, at a minimum of 90 and a maximum of 300. You can view the timer by examining it, unless the Proceed wire is cut. Once the timer hits zero, the bomb will detonate. + A bomb has a limited time, at a minimum of [protodata="SyndicateBomb" comp="OnUseTimerTrigger" member="ShortestDelayOption"/] seconds and a maximum of [protodata="SyndicateBomb" comp="OnUseTimerTrigger" member="LongestDelayOption"/] seconds. You can view the timer by examining it, unless the Proceed wire is cut. Once the timer hits zero, the bomb will detonate. ## Bolts By default, once armed, a bomb will bolt itself to the ground. You must find the BOLT wire and cut it to disable the bolts, after which you can unwrench it and throw it into space. From 8b2ea59515c6e7795d84b0fb79fe8fd622550cd4 Mon Sep 17 00:00:00 2001 From: lzk <124214523+lzk228@users.noreply.github.com> Date: Thu, 12 Sep 2024 12:36:41 +0200 Subject: [PATCH 003/138] don't apply traits for borg and ai (#31990) * doesn't apply traits for borg or ai * add some comment and summaries * weh weh * well ok Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com> --------- Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com> --- Content.Server/Traits/TraitSystem.cs | 9 ++++++++ Content.Shared/Roles/JobPrototype.cs | 21 +++++++++++++++++++ .../Prototypes/Roles/Jobs/Science/borg.yml | 2 ++ 3 files changed, 32 insertions(+) diff --git a/Content.Server/Traits/TraitSystem.cs b/Content.Server/Traits/TraitSystem.cs index 3bd540a3049..e19f736f067 100644 --- a/Content.Server/Traits/TraitSystem.cs +++ b/Content.Server/Traits/TraitSystem.cs @@ -1,6 +1,7 @@ using Content.Server.GameTicking; using Content.Shared.Hands.Components; using Content.Shared.Hands.EntitySystems; +using Content.Shared.Roles; using Content.Shared.Traits; using Content.Shared.Whitelist; using Robust.Shared.Prototypes; @@ -24,6 +25,14 @@ public override void Initialize() // When the player is spawned in, add all trait components selected during character creation private void OnPlayerSpawnComplete(PlayerSpawnCompleteEvent args) { + // Check if player's job allows to apply traits + if (args.JobId == null || + !_prototypeManager.TryIndex(args.JobId ?? string.Empty, out var protoJob) || + !protoJob.ApplyTraits) + { + return; + } + foreach (var traitId in args.Profile.TraitPreferences) { if (!_prototypeManager.TryIndex(traitId, out var traitPrototype)) diff --git a/Content.Shared/Roles/JobPrototype.cs b/Content.Shared/Roles/JobPrototype.cs index e7156b34c3b..1ca1600e770 100644 --- a/Content.Shared/Roles/JobPrototype.cs +++ b/Content.Shared/Roles/JobPrototype.cs @@ -20,6 +20,9 @@ public sealed partial class JobPrototype : IPrototype [DataField("playTimeTracker", required: true, customTypeSerializer: typeof(PrototypeIdSerializer))] public string PlayTimeTracker { get; private set; } = string.Empty; + /// + /// Who is the supervisor for this job. + /// [DataField("supervisors")] public string Supervisors { get; private set; } = "nobody"; @@ -41,18 +44,36 @@ public sealed partial class JobPrototype : IPrototype [ViewVariables(VVAccess.ReadOnly)] public string? LocalizedDescription => Description is null ? null : Loc.GetString(Description); + /// + /// Requirements for the job. + /// [DataField, Access(typeof(SharedRoleSystem), Other = AccessPermissions.None)] public HashSet? Requirements; + /// + /// When true - the station will have anouncement about arrival of this player. + /// [DataField("joinNotifyCrew")] public bool JoinNotifyCrew { get; private set; } = false; + /// + /// When true - the player will recieve a message about importancy of their job. + /// [DataField("requireAdminNotify")] public bool RequireAdminNotify { get; private set; } = false; + /// + /// Should this job appear in preferences menu? + /// [DataField("setPreference")] public bool SetPreference { get; private set; } = true; + /// + /// Should the selected traits be applied for this job? + /// + [DataField] + public bool ApplyTraits { get; private set; } = true; + /// /// Whether this job should show in the ID Card Console. /// If set to null, it will default to SetPreference's value. diff --git a/Resources/Prototypes/Roles/Jobs/Science/borg.yml b/Resources/Prototypes/Roles/Jobs/Science/borg.yml index fffeaff39c5..e35270d57dc 100644 --- a/Resources/Prototypes/Roles/Jobs/Science/borg.yml +++ b/Resources/Prototypes/Roles/Jobs/Science/borg.yml @@ -12,6 +12,7 @@ icon: JobIconStationAi supervisors: job-supervisors-rd jobEntity: StationAiBrain + applyTraits: false - type: job id: Borg @@ -25,3 +26,4 @@ icon: JobIconBorg supervisors: job-supervisors-rd jobEntity: PlayerBorgGeneric + applyTraits: false From 8df384fe6613fa481d7cd76a45cb50bf8fffdc8c Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 12 Sep 2024 10:37:48 +0000 Subject: [PATCH 004/138] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 925a7da9599..c93be023ae4 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: lzk228 - changes: - - message: Space Law book added to the game. - type: Add - id: 6859 - time: '2024-07-02T13:33:49.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29392 - author: Ko4erga changes: - message: Dropper can be placed in med belt, plant belt and chemistry bag. @@ -3913,3 +3906,10 @@ id: 7358 time: '2024-09-12T00:52:19.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/31842 +- author: lzk228 + changes: + - message: Borgs and Station AI will not receive selected in preferences traits. + type: Tweak + id: 7359 + time: '2024-09-12T10:36:41.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/31990 From b36efce3b1cb31c6e5b994a8d088fc63b1484f43 Mon Sep 17 00:00:00 2001 From: RobDemo <88208745+MrRobDemo@users.noreply.github.com> Date: Thu, 12 Sep 2024 15:51:41 +0300 Subject: [PATCH 005/138] Smart tomato pet (#31932) * SmartTomato * Fix * RemovingExtraLines * Update Resources/Locale/en-US/ghost/roles/ghost-role-component.ftl Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * Update Resources/Prototypes/Accents/full_replacements.yml Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * Update Resources/Prototypes/Entities/Mobs/NPCs/miscellaneous.yml Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * Update Resources/Prototypes/Entities/Mobs/NPCs/miscellaneous.yml Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * Update Resources/Prototypes/Entities/Mobs/NPCs/miscellaneous.yml Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> --------- Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com> Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> --- Resources/Locale/en-US/accent/accents.ftl | 7 +++ .../ghost/roles/ghost-role-component.ftl | 4 ++ .../Prototypes/Accents/full_replacements.yml | 9 ++++ .../Entities/Mobs/NPCs/miscellaneous.yml | 47 ++++++++++++++++++- 4 files changed, 66 insertions(+), 1 deletion(-) diff --git a/Resources/Locale/en-US/accent/accents.ftl b/Resources/Locale/en-US/accent/accents.ftl index 301c589449d..f54cecf7147 100644 --- a/Resources/Locale/en-US/accent/accents.ftl +++ b/Resources/Locale/en-US/accent/accents.ftl @@ -124,3 +124,10 @@ accent-words-nymph-1 = Chirp! accent-words-nymph-2 = Churr... accent-words-nymph-3 = Cheep? accent-words-nymph-4 = Chrrup! + +# TomatoKiller +accent-words-tomato-1 = Totato! +accent-words-tomato-2 = Trotect +accent-words-tomato-3 = Mastet? +accent-words-tomato-4 = Reaty! +accent-words-tomato-5 = Water... \ No newline at end of file diff --git a/Resources/Locale/en-US/ghost/roles/ghost-role-component.ftl b/Resources/Locale/en-US/ghost/roles/ghost-role-component.ftl index 45706130814..77d2645c4c5 100644 --- a/Resources/Locale/en-US/ghost/roles/ghost-role-component.ftl +++ b/Resources/Locale/en-US/ghost/roles/ghost-role-component.ftl @@ -306,3 +306,7 @@ ghost-role-information-pirate-captain-description = Argh matey! You are in charg ghost-role-information-artifact-name = Sentient Artifact ghost-role-information-artifact-description = Enact your eldritch whims. Forcibly activate your nodes for good or for evil. + +ghost-role-information-tomatokiller-name = Tomato killer +ghost-role-information-tomatokiller-description = This little tomato will serve the botanist for the rest of his life... that is, a couple of minutes + diff --git a/Resources/Prototypes/Accents/full_replacements.yml b/Resources/Prototypes/Accents/full_replacements.yml index 1d1efdcad0e..f495de250fc 100644 --- a/Resources/Prototypes/Accents/full_replacements.yml +++ b/Resources/Prototypes/Accents/full_replacements.yml @@ -174,3 +174,12 @@ - accent-words-nymph-2 - accent-words-nymph-3 - accent-words-nymph-4 + +- type: accent + id: tomatoKiller + fullReplacements: + - accent-words-tomato-1 + - accent-words-tomato-2 + - accent-words-tomato-3 + - accent-words-tomato-4 + - accent-words-tomato-5 diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/miscellaneous.yml b/Resources/Prototypes/Entities/Mobs/NPCs/miscellaneous.yml index 9f2f9516625..f10d03886a5 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/miscellaneous.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/miscellaneous.yml @@ -79,6 +79,51 @@ name: tomato killer description: Looks like it's not you eating tomatoes today, it's the tomatoes eating you. components: + - type: GhostRole + prob: 0.05 + makeSentient: true + allowSpeech: true + name: ghost-role-information-tomatokiller-name + description: ghost-role-information-tomatokiller-description + rules: ghost-role-information-familiar-rules + raffle: + settings: short + - type: GhostTakeoverAvailable + - type: CanEscapeInventory + baseResistTime: 3 + - type: Reactive + groups: + Flammable: [ Touch ] + Extinguish: [ Touch ] + reactions: + - reagents: [ Water ] + methods: [ Touch ] + effects: + - !type:HealthChange + scaleByQuantity: true + damage: + groups: + Brute: -0.25 + - reagents: [ Blood ] + methods: [ Touch ] + effects: + - !type:HealthChange + scaleByQuantity: true + damage: + groups: + Brute: -0.5 + Burn: -0.5 + - reagents: [ RobustHarvest ] + methods: [ Touch ] + effects: + - !type:HealthChange + scaleByQuantity: true + damage: + groups: + Brute: -2 + Burn: -2 + - type: ReplacementAccent + accent: tomatoKiller - type: Item - type: NpcFactionMember factions: @@ -175,4 +220,4 @@ types: Blunt: 0.11 - type: StaticPrice - price: 400 + price: 400 \ No newline at end of file From 3b5c3da4ab6b52694c513948c26de5d972f8a3c5 Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 12 Sep 2024 12:52:49 +0000 Subject: [PATCH 006/138] Automatic changelog update --- Resources/Changelog/Changelog.yml | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index c93be023ae4..05f1b46858a 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,13 +1,4 @@ Entries: -- author: Ko4erga - changes: - - message: Dropper can be placed in med belt, plant belt and chemistry bag. - type: Tweak - - message: Dropper size changed. - type: Tweak - id: 6860 - time: '2024-07-02T15:28:49.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29667 - author: Plykiya changes: - message: You now see pickup animations when stripping objects off of people. @@ -3913,3 +3904,15 @@ id: 7359 time: '2024-09-12T10:36:41.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/31990 +- author: MrRobDemo + changes: + - message: Added 5% chance to make killer tomatoes a ghost role. + type: Add + - message: Killer tomatoes can now heal from being splashed with water, blood or + RobustHarvest. + type: Add + - message: Killer tomatoes can now escape from inventory (only intelligent). + type: Tweak + id: 7360 + time: '2024-09-12T12:51:41.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/31932 From adfbc6efa778dc93811e028285e8ff01e9287445 Mon Sep 17 00:00:00 2001 From: ScarKy0 <106310278+ScarKy0@users.noreply.github.com> Date: Thu, 12 Sep 2024 17:28:54 +0200 Subject: [PATCH 007/138] Gave AI a comms console (#31852) * Updated sprites for AI HUD * Epic test fail * Merged AGhost actions and AI actions together again. * Seperate comms and bugfix. Fixed broadcast. * Stuffs * Update station_ai.yml * Update station_ai.yml * :| * Update silicon.yml * oopsie daisy * stuff * further stuff * oh my god * Appeasing the gods --- .../communications-console-component.ftl | 1 + Resources/Prototypes/Actions/station_ai.yml | 4 ++++ .../Prototypes/Entities/Mobs/Player/admin_ghost.yml | 12 ++++++------ .../Prototypes/Entities/Mobs/Player/silicon.yml | 9 +++++++++ 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/Resources/Locale/en-US/communications/communications-console-component.ftl b/Resources/Locale/en-US/communications/communications-console-component.ftl index 0d022ed5a6e..a757f9e0d10 100644 --- a/Resources/Locale/en-US/communications/communications-console-component.ftl +++ b/Resources/Locale/en-US/communications/communications-console-component.ftl @@ -24,3 +24,4 @@ comms-console-announcement-unknown-sender = Unknown comms-console-announcement-title-station = Communications Console comms-console-announcement-title-centcom = Central Command comms-console-announcement-title-nukie = Syndicate Nuclear Operative +comms-console-announcement-title-station-ai = Station AI diff --git a/Resources/Prototypes/Actions/station_ai.yml b/Resources/Prototypes/Actions/station_ai.yml index e2ce25de9d8..58513d7db16 100644 --- a/Resources/Prototypes/Actions/station_ai.yml +++ b/Resources/Prototypes/Actions/station_ai.yml @@ -5,6 +5,7 @@ description: Sends your eye back to the core. components: - type: InstantAction + priority: -10 itemIconStyle: BigAction icon: sprite: Interface/Actions/actions_ai.rsi @@ -17,6 +18,7 @@ description: Shows job icons for crew members. components: - type: InstantAction + priority: -5 itemIconStyle: BigAction icon: sprite: Interface/Actions/actions_ai.rsi @@ -31,6 +33,7 @@ description: Enable surveillance camera lights near wherever you're viewing. components: - type: InstantAction + priority: -6 itemIconStyle: BigAction icon: sprite: Interface/Actions/actions_ai.rsi @@ -56,6 +59,7 @@ description: View the laws that you must follow. components: - type: InstantAction + priority: -3 itemIconStyle: NoItem icon: sprite: Interface/Actions/actions_ai.rsi diff --git a/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml b/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml index 29495a977ef..af75c628362 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml @@ -111,10 +111,10 @@ description: View a communications interface. components: - type: InstantAction - icon: { sprite: Structures/Machines/parts.rsi, state: box_0 } - iconOn: Structures/Machines/parts.rsi/box_2.png + icon: { sprite: Interface/Actions/actions_ai.rsi, state: comms_console } + iconOn: Interface/Actions/actions_ai.rsi/comms_console.png keywords: [ "AI", "console", "interface" ] - priority: -10 + priority: -4 event: !type:ToggleIntrinsicUIEvent { key: enum.CommunicationsConsoleUiKey.Key } - type: entity @@ -126,7 +126,7 @@ icon: { sprite: Interface/Actions/actions_ai.rsi, state: mass_scanner } iconOn: Interface/Actions/actions_ai.rsi/mass_scanner.png keywords: [ "AI", "console", "interface" ] - priority: -10 + priority: -7 event: !type:ToggleIntrinsicUIEvent { key: enum.RadarConsoleUiKey.Key } - type: entity @@ -150,7 +150,7 @@ icon: { sprite: Interface/Actions/actions_ai.rsi, state: crew_monitor } iconOn: Interface/Actions/actions_ai.rsi/crew_monitor.png keywords: [ "AI", "console", "interface" ] - priority: -10 + priority: -9 event: !type:ToggleIntrinsicUIEvent { key: enum.CrewMonitoringUIKey.Key } - type: entity @@ -162,5 +162,5 @@ icon: { sprite: Interface/Actions/actions_ai.rsi, state: station_records } iconOn: Interface/Actions/actions_ai.rsi/station_records.png keywords: [ "AI", "console", "interface" ] - priority: -10 + priority: -8 event: !type:ToggleIntrinsicUIEvent { key: enum.GeneralStationRecordConsoleKey.Key } diff --git a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml index 601fa1f5c1b..62dbf3ee106 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml @@ -46,6 +46,8 @@ type: GeneralStationRecordConsoleBoundUserInterface enum.SiliconLawsUiKey.Key: type: SiliconLawBoundUserInterface + enum.CommunicationsConsoleUiKey.Key: + type: CommunicationsConsoleBoundUserInterface - type: IntrinsicUI uis: enum.RadarConsoleUiKey.Key: @@ -54,13 +56,20 @@ toggleAction: ActionAGhostShowCrewMonitoring enum.GeneralStationRecordConsoleKey.Key: toggleAction: ActionAGhostShowStationRecords + enum.CommunicationsConsoleUiKey.Key: + toggleAction: ActionAGhostShowCommunications - type: CrewMonitoringConsole - type: GeneralStationRecordConsole - type: DeviceNetwork deviceNetId: Wireless receiveFrequencyId: CrewMonitor + transmitFrequencyId: ShuttleTimer - type: RadarConsole followEntity: false + - type: CommunicationsConsole + canShuttle: false + title: comms-console-announcement-title-station-ai + color: "#2ed2fd" # Ai From 4b8510894fd098257e72bfcabad0ab570ba50d1c Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 12 Sep 2024 15:30:01 +0000 Subject: [PATCH 008/138] Automatic changelog update --- Resources/Changelog/Changelog.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 05f1b46858a..c3a2b47684e 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,13 +1,4 @@ Entries: -- author: Plykiya - changes: - - message: You now see pickup animations when stripping objects off of people. - type: Fix - - message: Thieving gloves no longer have a pickup animation when stripping people. - type: Fix - id: 6861 - time: '2024-07-03T00:01:59.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29665 - author: nikthechampiongr changes: - message: The Elite Syndicate hardsuit is now slightly slower. @@ -3916,3 +3907,12 @@ id: 7360 time: '2024-09-12T12:51:41.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/31932 +- author: ScarKy0 + changes: + - message: Station AI now has a comms console ability. + type: Add + - message: Station AI abilities now have a default order. + type: Tweak + id: 7361 + time: '2024-09-12T15:28:54.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/31852 From 1c6b9aaae7b2dd64ca7e53aeeeb8ebb1438adb4a Mon Sep 17 00:00:00 2001 From: Errant <35878406+Errant-4@users.noreply.github.com> Date: Thu, 12 Sep 2024 22:01:36 +0200 Subject: [PATCH 009/138] movercontroller namespace (#31749) --- .../Physics/Controllers/MoverController.cs | 201 +++-- .../Physics/Controllers/MoverController.cs | 849 +++++++++--------- .../Movement/Systems/SharedMoverController.cs | 761 ++++++++-------- 3 files changed, 904 insertions(+), 907 deletions(-) diff --git a/Content.Client/Physics/Controllers/MoverController.cs b/Content.Client/Physics/Controllers/MoverController.cs index 03df383eebc..c97110b208e 100644 --- a/Content.Client/Physics/Controllers/MoverController.cs +++ b/Content.Client/Physics/Controllers/MoverController.cs @@ -8,132 +8,131 @@ using Robust.Shared.Player; using Robust.Shared.Timing; -namespace Content.Client.Physics.Controllers +namespace Content.Client.Physics.Controllers; + +public sealed class MoverController : SharedMoverController { - public sealed class MoverController : SharedMoverController - { - [Dependency] private readonly IGameTiming _timing = default!; - [Dependency] private readonly IPlayerManager _playerManager = default!; + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly IPlayerManager _playerManager = default!; - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(OnRelayPlayerAttached); - SubscribeLocalEvent(OnRelayPlayerDetached); - SubscribeLocalEvent(OnPlayerAttached); - SubscribeLocalEvent(OnPlayerDetached); - - SubscribeLocalEvent(OnUpdatePredicted); - SubscribeLocalEvent(OnUpdateRelayTargetPredicted); - SubscribeLocalEvent(OnUpdatePullablePredicted); - } + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnRelayPlayerAttached); + SubscribeLocalEvent(OnRelayPlayerDetached); + SubscribeLocalEvent(OnPlayerAttached); + SubscribeLocalEvent(OnPlayerDetached); + + SubscribeLocalEvent(OnUpdatePredicted); + SubscribeLocalEvent(OnUpdateRelayTargetPredicted); + SubscribeLocalEvent(OnUpdatePullablePredicted); + } - private void OnUpdatePredicted(Entity entity, ref UpdateIsPredictedEvent args) - { - // Enable prediction if an entity is controlled by the player - if (entity.Owner == _playerManager.LocalEntity) - args.IsPredicted = true; - } + private void OnUpdatePredicted(Entity entity, ref UpdateIsPredictedEvent args) + { + // Enable prediction if an entity is controlled by the player + if (entity.Owner == _playerManager.LocalEntity) + args.IsPredicted = true; + } - private void OnUpdateRelayTargetPredicted(Entity entity, ref UpdateIsPredictedEvent args) - { - if (entity.Comp.Source == _playerManager.LocalEntity) - args.IsPredicted = true; - } + private void OnUpdateRelayTargetPredicted(Entity entity, ref UpdateIsPredictedEvent args) + { + if (entity.Comp.Source == _playerManager.LocalEntity) + args.IsPredicted = true; + } - private void OnUpdatePullablePredicted(Entity entity, ref UpdateIsPredictedEvent args) - { - // Enable prediction if an entity is being pulled by the player. - // Disable prediction if an entity is being pulled by some non-player entity. + private void OnUpdatePullablePredicted(Entity entity, ref UpdateIsPredictedEvent args) + { + // Enable prediction if an entity is being pulled by the player. + // Disable prediction if an entity is being pulled by some non-player entity. - if (entity.Comp.Puller == _playerManager.LocalEntity) - args.IsPredicted = true; - else if (entity.Comp.Puller != null) - args.BlockPrediction = true; + if (entity.Comp.Puller == _playerManager.LocalEntity) + args.IsPredicted = true; + else if (entity.Comp.Puller != null) + args.BlockPrediction = true; - // TODO recursive pulling checks? - // What if the entity is being pulled by a vehicle controlled by the player? - } + // TODO recursive pulling checks? + // What if the entity is being pulled by a vehicle controlled by the player? + } - private void OnRelayPlayerAttached(Entity entity, ref LocalPlayerAttachedEvent args) - { - Physics.UpdateIsPredicted(entity.Owner); - Physics.UpdateIsPredicted(entity.Comp.RelayEntity); - if (MoverQuery.TryGetComponent(entity.Comp.RelayEntity, out var inputMover)) - SetMoveInput((entity.Comp.RelayEntity, inputMover), MoveButtons.None); - } + private void OnRelayPlayerAttached(Entity entity, ref LocalPlayerAttachedEvent args) + { + Physics.UpdateIsPredicted(entity.Owner); + Physics.UpdateIsPredicted(entity.Comp.RelayEntity); + if (MoverQuery.TryGetComponent(entity.Comp.RelayEntity, out var inputMover)) + SetMoveInput((entity.Comp.RelayEntity, inputMover), MoveButtons.None); + } - private void OnRelayPlayerDetached(Entity entity, ref LocalPlayerDetachedEvent args) - { - Physics.UpdateIsPredicted(entity.Owner); - Physics.UpdateIsPredicted(entity.Comp.RelayEntity); - if (MoverQuery.TryGetComponent(entity.Comp.RelayEntity, out var inputMover)) - SetMoveInput((entity.Comp.RelayEntity, inputMover), MoveButtons.None); - } + private void OnRelayPlayerDetached(Entity entity, ref LocalPlayerDetachedEvent args) + { + Physics.UpdateIsPredicted(entity.Owner); + Physics.UpdateIsPredicted(entity.Comp.RelayEntity); + if (MoverQuery.TryGetComponent(entity.Comp.RelayEntity, out var inputMover)) + SetMoveInput((entity.Comp.RelayEntity, inputMover), MoveButtons.None); + } - private void OnPlayerAttached(Entity entity, ref LocalPlayerAttachedEvent args) - { - SetMoveInput(entity, MoveButtons.None); - } + private void OnPlayerAttached(Entity entity, ref LocalPlayerAttachedEvent args) + { + SetMoveInput(entity, MoveButtons.None); + } - private void OnPlayerDetached(Entity entity, ref LocalPlayerDetachedEvent args) - { - SetMoveInput(entity, MoveButtons.None); - } + private void OnPlayerDetached(Entity entity, ref LocalPlayerDetachedEvent args) + { + SetMoveInput(entity, MoveButtons.None); + } - public override void UpdateBeforeSolve(bool prediction, float frameTime) - { - base.UpdateBeforeSolve(prediction, frameTime); + public override void UpdateBeforeSolve(bool prediction, float frameTime) + { + base.UpdateBeforeSolve(prediction, frameTime); - if (_playerManager.LocalEntity is not {Valid: true} player) - return; + if (_playerManager.LocalEntity is not {Valid: true} player) + return; - if (RelayQuery.TryGetComponent(player, out var relayMover)) - HandleClientsideMovement(relayMover.RelayEntity, frameTime); + if (RelayQuery.TryGetComponent(player, out var relayMover)) + HandleClientsideMovement(relayMover.RelayEntity, frameTime); - HandleClientsideMovement(player, frameTime); - } + HandleClientsideMovement(player, frameTime); + } - private void HandleClientsideMovement(EntityUid player, float frameTime) + private void HandleClientsideMovement(EntityUid player, float frameTime) + { + if (!MoverQuery.TryGetComponent(player, out var mover) || + !XformQuery.TryGetComponent(player, out var xform)) { - if (!MoverQuery.TryGetComponent(player, out var mover) || - !XformQuery.TryGetComponent(player, out var xform)) - { - return; - } - - var physicsUid = player; - PhysicsComponent? body; - var xformMover = xform; + return; + } - if (mover.ToParent && RelayQuery.HasComponent(xform.ParentUid)) - { - if (!PhysicsQuery.TryGetComponent(xform.ParentUid, out body) || - !XformQuery.TryGetComponent(xform.ParentUid, out xformMover)) - { - return; - } + var physicsUid = player; + PhysicsComponent? body; + var xformMover = xform; - physicsUid = xform.ParentUid; - } - else if (!PhysicsQuery.TryGetComponent(player, out body)) + if (mover.ToParent && RelayQuery.HasComponent(xform.ParentUid)) + { + if (!PhysicsQuery.TryGetComponent(xform.ParentUid, out body) || + !XformQuery.TryGetComponent(xform.ParentUid, out xformMover)) { return; } - // Server-side should just be handled on its own so we'll just do this shizznit - HandleMobMovement( - player, - mover, - physicsUid, - body, - xformMover, - frameTime); + physicsUid = xform.ParentUid; } - - protected override bool CanSound() + else if (!PhysicsQuery.TryGetComponent(player, out body)) { - return _timing is { IsFirstTimePredicted: true, InSimulation: true }; + return; } + + // Server-side should just be handled on its own so we'll just do this shizznit + HandleMobMovement( + player, + mover, + physicsUid, + body, + xformMover, + frameTime); + } + + protected override bool CanSound() + { + return _timing is { IsFirstTimePredicted: true, InSimulation: true }; } } diff --git a/Content.Server/Physics/Controllers/MoverController.cs b/Content.Server/Physics/Controllers/MoverController.cs index 19d58438b35..f927e717a9d 100644 --- a/Content.Server/Physics/Controllers/MoverController.cs +++ b/Content.Server/Physics/Controllers/MoverController.cs @@ -12,560 +12,559 @@ using DependencyAttribute = Robust.Shared.IoC.DependencyAttribute; using Robust.Shared.Map.Components; -namespace Content.Server.Physics.Controllers +namespace Content.Server.Physics.Controllers; + +public sealed class MoverController : SharedMoverController { - public sealed class MoverController : SharedMoverController + [Dependency] private readonly ThrusterSystem _thruster = default!; + [Dependency] private readonly SharedTransformSystem _xformSystem = default!; + + private Dictionary)> _shuttlePilots = new(); + + public override void Initialize() { - [Dependency] private readonly ThrusterSystem _thruster = default!; - [Dependency] private readonly SharedTransformSystem _xformSystem = default!; + base.Initialize(); + SubscribeLocalEvent(OnRelayPlayerAttached); + SubscribeLocalEvent(OnRelayPlayerDetached); + SubscribeLocalEvent(OnPlayerAttached); + SubscribeLocalEvent(OnPlayerDetached); + } - private Dictionary)> _shuttlePilots = new(); + private void OnRelayPlayerAttached(Entity entity, ref PlayerAttachedEvent args) + { + if (MoverQuery.TryGetComponent(entity.Comp.RelayEntity, out var inputMover)) + SetMoveInput((entity.Comp.RelayEntity, inputMover), MoveButtons.None); + } - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(OnRelayPlayerAttached); - SubscribeLocalEvent(OnRelayPlayerDetached); - SubscribeLocalEvent(OnPlayerAttached); - SubscribeLocalEvent(OnPlayerDetached); - } + private void OnRelayPlayerDetached(Entity entity, ref PlayerDetachedEvent args) + { + if (MoverQuery.TryGetComponent(entity.Comp.RelayEntity, out var inputMover)) + SetMoveInput((entity.Comp.RelayEntity, inputMover), MoveButtons.None); + } - private void OnRelayPlayerAttached(Entity entity, ref PlayerAttachedEvent args) - { - if (MoverQuery.TryGetComponent(entity.Comp.RelayEntity, out var inputMover)) - SetMoveInput((entity.Comp.RelayEntity, inputMover), MoveButtons.None); - } + private void OnPlayerAttached(Entity entity, ref PlayerAttachedEvent args) + { + SetMoveInput(entity, MoveButtons.None); + } - private void OnRelayPlayerDetached(Entity entity, ref PlayerDetachedEvent args) - { - if (MoverQuery.TryGetComponent(entity.Comp.RelayEntity, out var inputMover)) - SetMoveInput((entity.Comp.RelayEntity, inputMover), MoveButtons.None); - } + private void OnPlayerDetached(Entity entity, ref PlayerDetachedEvent args) + { + SetMoveInput(entity, MoveButtons.None); + } - private void OnPlayerAttached(Entity entity, ref PlayerAttachedEvent args) - { - SetMoveInput(entity, MoveButtons.None); - } + protected override bool CanSound() + { + return true; + } - private void OnPlayerDetached(Entity entity, ref PlayerDetachedEvent args) - { - SetMoveInput(entity, MoveButtons.None); - } + public override void UpdateBeforeSolve(bool prediction, float frameTime) + { + base.UpdateBeforeSolve(prediction, frameTime); - protected override bool CanSound() - { - return true; - } + var inputQueryEnumerator = AllEntityQuery(); - public override void UpdateBeforeSolve(bool prediction, float frameTime) + while (inputQueryEnumerator.MoveNext(out var uid, out var mover)) { - base.UpdateBeforeSolve(prediction, frameTime); + var physicsUid = uid; - var inputQueryEnumerator = AllEntityQuery(); + if (RelayQuery.HasComponent(uid)) + continue; - while (inputQueryEnumerator.MoveNext(out var uid, out var mover)) + if (!XformQuery.TryGetComponent(uid, out var xform)) { - var physicsUid = uid; - - if (RelayQuery.HasComponent(uid)) - continue; - - if (!XformQuery.TryGetComponent(uid, out var xform)) - { - continue; - } - - PhysicsComponent? body; - var xformMover = xform; + continue; + } - if (mover.ToParent && RelayQuery.HasComponent(xform.ParentUid)) - { - if (!PhysicsQuery.TryGetComponent(xform.ParentUid, out body) || - !XformQuery.TryGetComponent(xform.ParentUid, out xformMover)) - { - continue; - } + PhysicsComponent? body; + var xformMover = xform; - physicsUid = xform.ParentUid; - } - else if (!PhysicsQuery.TryGetComponent(uid, out body)) + if (mover.ToParent && RelayQuery.HasComponent(xform.ParentUid)) + { + if (!PhysicsQuery.TryGetComponent(xform.ParentUid, out body) || + !XformQuery.TryGetComponent(xform.ParentUid, out xformMover)) { continue; } - HandleMobMovement(uid, - mover, - physicsUid, - body, - xformMover, - frameTime); + physicsUid = xform.ParentUid; } - - HandleShuttleMovement(frameTime); - } - - public (Vector2 Strafe, float Rotation, float Brakes) GetPilotVelocityInput(PilotComponent component) - { - if (!Timing.InSimulation) + else if (!PhysicsQuery.TryGetComponent(uid, out body)) { - // Outside of simulation we'll be running client predicted movement per-frame. - // So return a full-length vector as if it's a full tick. - // Physics system will have the correct time step anyways. - ResetSubtick(component); - ApplyTick(component, 1f); - return (component.CurTickStrafeMovement, component.CurTickRotationMovement, component.CurTickBraking); + continue; } - float remainingFraction; - - if (Timing.CurTick > component.LastInputTick) - { - component.CurTickStrafeMovement = Vector2.Zero; - component.CurTickRotationMovement = 0f; - component.CurTickBraking = 0f; - remainingFraction = 1; - } - else - { - remainingFraction = (ushort.MaxValue - component.LastInputSubTick) / (float) ushort.MaxValue; - } + HandleMobMovement(uid, + mover, + physicsUid, + body, + xformMover, + frameTime); + } - ApplyTick(component, remainingFraction); + HandleShuttleMovement(frameTime); + } - // Logger.Info($"{curDir}{walk}{sprint}"); + public (Vector2 Strafe, float Rotation, float Brakes) GetPilotVelocityInput(PilotComponent component) + { + if (!Timing.InSimulation) + { + // Outside of simulation we'll be running client predicted movement per-frame. + // So return a full-length vector as if it's a full tick. + // Physics system will have the correct time step anyways. + ResetSubtick(component); + ApplyTick(component, 1f); return (component.CurTickStrafeMovement, component.CurTickRotationMovement, component.CurTickBraking); } - private void ResetSubtick(PilotComponent component) - { - if (Timing.CurTick <= component.LastInputTick) return; + float remainingFraction; + if (Timing.CurTick > component.LastInputTick) + { component.CurTickStrafeMovement = Vector2.Zero; component.CurTickRotationMovement = 0f; component.CurTickBraking = 0f; - component.LastInputTick = Timing.CurTick; - component.LastInputSubTick = 0; + remainingFraction = 1; + } + else + { + remainingFraction = (ushort.MaxValue - component.LastInputSubTick) / (float) ushort.MaxValue; } - protected override void HandleShuttleInput(EntityUid uid, ShuttleButtons button, ushort subTick, bool state) + ApplyTick(component, remainingFraction); + + // Logger.Info($"{curDir}{walk}{sprint}"); + return (component.CurTickStrafeMovement, component.CurTickRotationMovement, component.CurTickBraking); + } + + private void ResetSubtick(PilotComponent component) + { + if (Timing.CurTick <= component.LastInputTick) return; + + component.CurTickStrafeMovement = Vector2.Zero; + component.CurTickRotationMovement = 0f; + component.CurTickBraking = 0f; + component.LastInputTick = Timing.CurTick; + component.LastInputSubTick = 0; + } + + protected override void HandleShuttleInput(EntityUid uid, ShuttleButtons button, ushort subTick, bool state) + { + if (!TryComp(uid, out var pilot) || pilot.Console == null) + return; + + ResetSubtick(pilot); + + if (subTick >= pilot.LastInputSubTick) { - if (!TryComp(uid, out var pilot) || pilot.Console == null) - return; + var fraction = (subTick - pilot.LastInputSubTick) / (float) ushort.MaxValue; - ResetSubtick(pilot); + ApplyTick(pilot, fraction); + pilot.LastInputSubTick = subTick; + } - if (subTick >= pilot.LastInputSubTick) - { - var fraction = (subTick - pilot.LastInputSubTick) / (float) ushort.MaxValue; + var buttons = pilot.HeldButtons; - ApplyTick(pilot, fraction); - pilot.LastInputSubTick = subTick; - } + if (state) + { + buttons |= button; + } + else + { + buttons &= ~button; + } - var buttons = pilot.HeldButtons; + pilot.HeldButtons = buttons; + } - if (state) - { - buttons |= button; - } - else - { - buttons &= ~button; - } + private static void ApplyTick(PilotComponent component, float fraction) + { + var x = 0; + var y = 0; + var rot = 0; + int brake; - pilot.HeldButtons = buttons; + if ((component.HeldButtons & ShuttleButtons.StrafeLeft) != 0x0) + { + x -= 1; } - private static void ApplyTick(PilotComponent component, float fraction) + if ((component.HeldButtons & ShuttleButtons.StrafeRight) != 0x0) { - var x = 0; - var y = 0; - var rot = 0; - int brake; + x += 1; + } - if ((component.HeldButtons & ShuttleButtons.StrafeLeft) != 0x0) - { - x -= 1; - } + component.CurTickStrafeMovement.X += x * fraction; - if ((component.HeldButtons & ShuttleButtons.StrafeRight) != 0x0) - { - x += 1; - } + if ((component.HeldButtons & ShuttleButtons.StrafeUp) != 0x0) + { + y += 1; + } - component.CurTickStrafeMovement.X += x * fraction; + if ((component.HeldButtons & ShuttleButtons.StrafeDown) != 0x0) + { + y -= 1; + } - if ((component.HeldButtons & ShuttleButtons.StrafeUp) != 0x0) - { - y += 1; - } + component.CurTickStrafeMovement.Y += y * fraction; - if ((component.HeldButtons & ShuttleButtons.StrafeDown) != 0x0) - { - y -= 1; - } + if ((component.HeldButtons & ShuttleButtons.RotateLeft) != 0x0) + { + rot -= 1; + } - component.CurTickStrafeMovement.Y += y * fraction; + if ((component.HeldButtons & ShuttleButtons.RotateRight) != 0x0) + { + rot += 1; + } - if ((component.HeldButtons & ShuttleButtons.RotateLeft) != 0x0) - { - rot -= 1; - } + component.CurTickRotationMovement += rot * fraction; - if ((component.HeldButtons & ShuttleButtons.RotateRight) != 0x0) - { - rot += 1; - } + if ((component.HeldButtons & ShuttleButtons.Brake) != 0x0) + { + brake = 1; + } + else + { + brake = 0; + } - component.CurTickRotationMovement += rot * fraction; + component.CurTickBraking += brake * fraction; + } + + /// + /// Helper function to extrapolate max velocity for a given Vector2 (really, its angle) and shuttle. + /// + private Vector2 ObtainMaxVel(Vector2 vel, ShuttleComponent shuttle) + { + if (vel.Length() == 0f) + return Vector2.Zero; + + // this math could PROBABLY be simplified for performance + // probably + // __________________________________ + // / / __ __ \2 / __ __ \2 + // O = I : _ / |I * | 1/H | | + |I * | 0 | | + // V \ |_ 0 _| / \ |_1/V_| / + + var horizIndex = vel.X > 0 ? 1 : 3; // east else west + var vertIndex = vel.Y > 0 ? 2 : 0; // north else south + var horizComp = vel.X != 0 ? MathF.Pow(Vector2.Dot(vel, new (shuttle.LinearThrust[horizIndex] / shuttle.LinearThrust[horizIndex], 0f)), 2) : 0; + var vertComp = vel.Y != 0 ? MathF.Pow(Vector2.Dot(vel, new (0f, shuttle.LinearThrust[vertIndex] / shuttle.LinearThrust[vertIndex])), 2) : 0; + + return shuttle.BaseMaxLinearVelocity * vel * MathF.ReciprocalSqrtEstimate(horizComp + vertComp); + } + + private void HandleShuttleMovement(float frameTime) + { + var newPilots = new Dictionary)>(); + + // We just mark off their movement and the shuttle itself does its own movement + var activePilotQuery = EntityQueryEnumerator(); + var shuttleQuery = GetEntityQuery(); + while (activePilotQuery.MoveNext(out var uid, out var pilot, out var mover)) + { + var consoleEnt = pilot.Console; - if ((component.HeldButtons & ShuttleButtons.Brake) != 0x0) + // TODO: This is terrible. Just make a new mover and also make it remote piloting + device networks + if (TryComp(consoleEnt, out var cargoConsole)) { - brake = 1; + consoleEnt = cargoConsole.Entity; } - else + + if (!TryComp(consoleEnt, out TransformComponent? xform)) continue; + + var gridId = xform.GridUid; + // This tries to see if the grid is a shuttle and if the console should work. + if (!TryComp(gridId, out var _) || + !shuttleQuery.TryGetComponent(gridId, out var shuttleComponent) || + !shuttleComponent.Enabled) + continue; + + if (!newPilots.TryGetValue(gridId!.Value, out var pilots)) { - brake = 0; + pilots = (shuttleComponent, new List<(EntityUid, PilotComponent, InputMoverComponent, TransformComponent)>()); + newPilots[gridId.Value] = pilots; } - component.CurTickBraking += brake * fraction; + pilots.Item2.Add((uid, pilot, mover, xform)); } - /// - /// Helper function to extrapolate max velocity for a given Vector2 (really, its angle) and shuttle. - /// - private Vector2 ObtainMaxVel(Vector2 vel, ShuttleComponent shuttle) + // Reset inputs for non-piloted shuttles. + foreach (var (shuttleUid, (shuttle, _)) in _shuttlePilots) { - if (vel.Length() == 0f) - return Vector2.Zero; - - // this math could PROBABLY be simplified for performance - // probably - // __________________________________ - // / / __ __ \2 / __ __ \2 - // O = I : _ / |I * | 1/H | | + |I * | 0 | | - // V \ |_ 0 _| / \ |_1/V_| / - - var horizIndex = vel.X > 0 ? 1 : 3; // east else west - var vertIndex = vel.Y > 0 ? 2 : 0; // north else south - var horizComp = vel.X != 0 ? MathF.Pow(Vector2.Dot(vel, new (shuttle.LinearThrust[horizIndex] / shuttle.LinearThrust[horizIndex], 0f)), 2) : 0; - var vertComp = vel.Y != 0 ? MathF.Pow(Vector2.Dot(vel, new (0f, shuttle.LinearThrust[vertIndex] / shuttle.LinearThrust[vertIndex])), 2) : 0; - - return shuttle.BaseMaxLinearVelocity * vel * MathF.ReciprocalSqrtEstimate(horizComp + vertComp); + if (newPilots.ContainsKey(shuttleUid) || CanPilot(shuttleUid)) + continue; + + _thruster.DisableLinearThrusters(shuttle); } - private void HandleShuttleMovement(float frameTime) + _shuttlePilots = newPilots; + + // Collate all of the linear / angular velocites for a shuttle + // then do the movement input once for it. + var xformQuery = GetEntityQuery(); + foreach (var (shuttleUid, (shuttle, pilots)) in _shuttlePilots) { - var newPilots = new Dictionary)>(); + if (Paused(shuttleUid) || CanPilot(shuttleUid) || !TryComp(shuttleUid, out var body)) + continue; - // We just mark off their movement and the shuttle itself does its own movement - var activePilotQuery = EntityQueryEnumerator(); - var shuttleQuery = GetEntityQuery(); - while (activePilotQuery.MoveNext(out var uid, out var pilot, out var mover)) + var shuttleNorthAngle = _xformSystem.GetWorldRotation(shuttleUid, xformQuery); + + // Collate movement linear and angular inputs together + var linearInput = Vector2.Zero; + var brakeInput = 0f; + var angularInput = 0f; + + foreach (var (pilotUid, pilot, _, consoleXform) in pilots) { - var consoleEnt = pilot.Console; + var (strafe, rotation, brakes) = GetPilotVelocityInput(pilot); - // TODO: This is terrible. Just make a new mover and also make it remote piloting + device networks - if (TryComp(consoleEnt, out var cargoConsole)) + if (brakes > 0f) { - consoleEnt = cargoConsole.Entity; + brakeInput += brakes; } - if (!TryComp(consoleEnt, out TransformComponent? xform)) continue; - - var gridId = xform.GridUid; - // This tries to see if the grid is a shuttle and if the console should work. - if (!TryComp(gridId, out var _) || - !shuttleQuery.TryGetComponent(gridId, out var shuttleComponent) || - !shuttleComponent.Enabled) - continue; - - if (!newPilots.TryGetValue(gridId!.Value, out var pilots)) + if (strafe.Length() > 0f) { - pilots = (shuttleComponent, new List<(EntityUid, PilotComponent, InputMoverComponent, TransformComponent)>()); - newPilots[gridId.Value] = pilots; + var offsetRotation = consoleXform.LocalRotation; + linearInput += offsetRotation.RotateVec(strafe); } - pilots.Item2.Add((uid, pilot, mover, xform)); - } - - // Reset inputs for non-piloted shuttles. - foreach (var (shuttleUid, (shuttle, _)) in _shuttlePilots) - { - if (newPilots.ContainsKey(shuttleUid) || CanPilot(shuttleUid)) - continue; - - _thruster.DisableLinearThrusters(shuttle); + if (rotation != 0f) + { + angularInput += rotation; + } } - _shuttlePilots = newPilots; + var count = pilots.Count; + linearInput /= count; + angularInput /= count; + brakeInput /= count; - // Collate all of the linear / angular velocites for a shuttle - // then do the movement input once for it. - var xformQuery = GetEntityQuery(); - foreach (var (shuttleUid, (shuttle, pilots)) in _shuttlePilots) + // Handle shuttle movement + if (brakeInput > 0f) { - if (Paused(shuttleUid) || CanPilot(shuttleUid) || !TryComp(shuttleUid, out var body)) - continue; - - var shuttleNorthAngle = _xformSystem.GetWorldRotation(shuttleUid, xformQuery); - - // Collate movement linear and angular inputs together - var linearInput = Vector2.Zero; - var brakeInput = 0f; - var angularInput = 0f; - - foreach (var (pilotUid, pilot, _, consoleXform) in pilots) + if (body.LinearVelocity.Length() > 0f) { - var (strafe, rotation, brakes) = GetPilotVelocityInput(pilot); + // Minimum brake velocity for a direction to show its thrust appearance. + const float appearanceThreshold = 0.1f; - if (brakes > 0f) - { - brakeInput += brakes; - } - - if (strafe.Length() > 0f) - { - var offsetRotation = consoleXform.LocalRotation; - linearInput += offsetRotation.RotateVec(strafe); - } + // Get velocity relative to the shuttle so we know which thrusters to fire + var shuttleVelocity = (-shuttleNorthAngle).RotateVec(body.LinearVelocity); + var force = Vector2.Zero; - if (rotation != 0f) + if (shuttleVelocity.X < 0f) { - angularInput += rotation; - } - } + _thruster.DisableLinearThrustDirection(shuttle, DirectionFlag.West); - var count = pilots.Count; - linearInput /= count; - angularInput /= count; - brakeInput /= count; + if (shuttleVelocity.X < -appearanceThreshold) + _thruster.EnableLinearThrustDirection(shuttle, DirectionFlag.East); - // Handle shuttle movement - if (brakeInput > 0f) - { - if (body.LinearVelocity.Length() > 0f) + var index = (int) Math.Log2((int) DirectionFlag.East); + force.X += shuttle.LinearThrust[index]; + } + else if (shuttleVelocity.X > 0f) { - // Minimum brake velocity for a direction to show its thrust appearance. - const float appearanceThreshold = 0.1f; + _thruster.DisableLinearThrustDirection(shuttle, DirectionFlag.East); - // Get velocity relative to the shuttle so we know which thrusters to fire - var shuttleVelocity = (-shuttleNorthAngle).RotateVec(body.LinearVelocity); - var force = Vector2.Zero; + if (shuttleVelocity.X > appearanceThreshold) + _thruster.EnableLinearThrustDirection(shuttle, DirectionFlag.West); - if (shuttleVelocity.X < 0f) - { - _thruster.DisableLinearThrustDirection(shuttle, DirectionFlag.West); - - if (shuttleVelocity.X < -appearanceThreshold) - _thruster.EnableLinearThrustDirection(shuttle, DirectionFlag.East); - - var index = (int) Math.Log2((int) DirectionFlag.East); - force.X += shuttle.LinearThrust[index]; - } - else if (shuttleVelocity.X > 0f) - { - _thruster.DisableLinearThrustDirection(shuttle, DirectionFlag.East); + var index = (int) Math.Log2((int) DirectionFlag.West); + force.X -= shuttle.LinearThrust[index]; + } - if (shuttleVelocity.X > appearanceThreshold) - _thruster.EnableLinearThrustDirection(shuttle, DirectionFlag.West); + if (shuttleVelocity.Y < 0f) + { + _thruster.DisableLinearThrustDirection(shuttle, DirectionFlag.South); - var index = (int) Math.Log2((int) DirectionFlag.West); - force.X -= shuttle.LinearThrust[index]; - } + if (shuttleVelocity.Y < -appearanceThreshold) + _thruster.EnableLinearThrustDirection(shuttle, DirectionFlag.North); - if (shuttleVelocity.Y < 0f) - { - _thruster.DisableLinearThrustDirection(shuttle, DirectionFlag.South); + var index = (int) Math.Log2((int) DirectionFlag.North); + force.Y += shuttle.LinearThrust[index]; + } + else if (shuttleVelocity.Y > 0f) + { + _thruster.DisableLinearThrustDirection(shuttle, DirectionFlag.North); - if (shuttleVelocity.Y < -appearanceThreshold) - _thruster.EnableLinearThrustDirection(shuttle, DirectionFlag.North); + if (shuttleVelocity.Y > appearanceThreshold) + _thruster.EnableLinearThrustDirection(shuttle, DirectionFlag.South); - var index = (int) Math.Log2((int) DirectionFlag.North); - force.Y += shuttle.LinearThrust[index]; - } - else if (shuttleVelocity.Y > 0f) - { - _thruster.DisableLinearThrustDirection(shuttle, DirectionFlag.North); + var index = (int) Math.Log2((int) DirectionFlag.South); + force.Y -= shuttle.LinearThrust[index]; + } - if (shuttleVelocity.Y > appearanceThreshold) - _thruster.EnableLinearThrustDirection(shuttle, DirectionFlag.South); + var impulse = force * brakeInput * ShuttleComponent.BrakeCoefficient; + impulse = shuttleNorthAngle.RotateVec(impulse); + var forceMul = frameTime * body.InvMass; + var maxVelocity = (-body.LinearVelocity).Length() / forceMul; - var index = (int) Math.Log2((int) DirectionFlag.South); - force.Y -= shuttle.LinearThrust[index]; - } + // Don't overshoot + if (impulse.Length() > maxVelocity) + impulse = impulse.Normalized() * maxVelocity; - var impulse = force * brakeInput * ShuttleComponent.BrakeCoefficient; - impulse = shuttleNorthAngle.RotateVec(impulse); - var forceMul = frameTime * body.InvMass; - var maxVelocity = (-body.LinearVelocity).Length() / forceMul; + PhysicsSystem.ApplyForce(shuttleUid, impulse, body: body); + } + else + { + _thruster.DisableLinearThrusters(shuttle); + } - // Don't overshoot - if (impulse.Length() > maxVelocity) - impulse = impulse.Normalized() * maxVelocity; + if (body.AngularVelocity != 0f) + { + var torque = shuttle.AngularThrust * brakeInput * (body.AngularVelocity > 0f ? -1f : 1f) * ShuttleComponent.BrakeCoefficient; + var torqueMul = body.InvI * frameTime; - PhysicsSystem.ApplyForce(shuttleUid, impulse, body: body); + if (body.AngularVelocity > 0f) + { + torque = MathF.Max(-body.AngularVelocity / torqueMul, torque); } else { - _thruster.DisableLinearThrusters(shuttle); + torque = MathF.Min(-body.AngularVelocity / torqueMul, torque); } - if (body.AngularVelocity != 0f) - { - var torque = shuttle.AngularThrust * brakeInput * (body.AngularVelocity > 0f ? -1f : 1f) * ShuttleComponent.BrakeCoefficient; - var torqueMul = body.InvI * frameTime; - - if (body.AngularVelocity > 0f) - { - torque = MathF.Max(-body.AngularVelocity / torqueMul, torque); - } - else - { - torque = MathF.Min(-body.AngularVelocity / torqueMul, torque); - } - - if (!torque.Equals(0f)) - { - PhysicsSystem.ApplyTorque(shuttleUid, torque, body: body); - _thruster.SetAngularThrust(shuttle, true); - } - } - else + if (!torque.Equals(0f)) { - _thruster.SetAngularThrust(shuttle, false); + PhysicsSystem.ApplyTorque(shuttleUid, torque, body: body); + _thruster.SetAngularThrust(shuttle, true); } } - - if (linearInput.Length().Equals(0f)) + else { - PhysicsSystem.SetSleepingAllowed(shuttleUid, body, true); - - if (brakeInput.Equals(0f)) - _thruster.DisableLinearThrusters(shuttle); + _thruster.SetAngularThrust(shuttle, false); } - else + } + + if (linearInput.Length().Equals(0f)) + { + PhysicsSystem.SetSleepingAllowed(shuttleUid, body, true); + + if (brakeInput.Equals(0f)) + _thruster.DisableLinearThrusters(shuttle); + } + else + { + PhysicsSystem.SetSleepingAllowed(shuttleUid, body, false); + var angle = linearInput.ToWorldAngle(); + var linearDir = angle.GetDir(); + var dockFlag = linearDir.AsFlag(); + var totalForce = Vector2.Zero; + + // Won't just do cardinal directions. + foreach (DirectionFlag dir in Enum.GetValues(typeof(DirectionFlag))) { - PhysicsSystem.SetSleepingAllowed(shuttleUid, body, false); - var angle = linearInput.ToWorldAngle(); - var linearDir = angle.GetDir(); - var dockFlag = linearDir.AsFlag(); - var totalForce = Vector2.Zero; - - // Won't just do cardinal directions. - foreach (DirectionFlag dir in Enum.GetValues(typeof(DirectionFlag))) + // Brain no worky but I just want cardinals + switch (dir) { - // Brain no worky but I just want cardinals - switch (dir) - { - case DirectionFlag.South: - case DirectionFlag.East: - case DirectionFlag.North: - case DirectionFlag.West: - break; - default: - continue; - } - - if ((dir & dockFlag) == 0x0) - { - _thruster.DisableLinearThrustDirection(shuttle, dir); + case DirectionFlag.South: + case DirectionFlag.East: + case DirectionFlag.North: + case DirectionFlag.West: + break; + default: continue; - } - - var force = Vector2.Zero; - var index = (int) Math.Log2((int) dir); - var thrust = shuttle.LinearThrust[index]; - - switch (dir) - { - case DirectionFlag.North: - force.Y += thrust; - break; - case DirectionFlag.South: - force.Y -= thrust; - break; - case DirectionFlag.East: - force.X += thrust; - break; - case DirectionFlag.West: - force.X -= thrust; - break; - default: - throw new ArgumentOutOfRangeException($"Attempted to apply thrust to shuttle {shuttleUid} along invalid dir {dir}."); - } - - _thruster.EnableLinearThrustDirection(shuttle, dir); - var impulse = force * linearInput.Length(); - totalForce += impulse; } - var forceMul = frameTime * body.InvMass; + if ((dir & dockFlag) == 0x0) + { + _thruster.DisableLinearThrustDirection(shuttle, dir); + continue; + } - var localVel = (-shuttleNorthAngle).RotateVec(body.LinearVelocity); - var maxVelocity = ObtainMaxVel(localVel, shuttle); // max for current travel dir - var maxWishVelocity = ObtainMaxVel(totalForce, shuttle); - var properAccel = (maxWishVelocity - localVel) / forceMul; + var force = Vector2.Zero; + var index = (int) Math.Log2((int) dir); + var thrust = shuttle.LinearThrust[index]; - var finalForce = Vector2Dot(totalForce, properAccel.Normalized()) * properAccel.Normalized(); + switch (dir) + { + case DirectionFlag.North: + force.Y += thrust; + break; + case DirectionFlag.South: + force.Y -= thrust; + break; + case DirectionFlag.East: + force.X += thrust; + break; + case DirectionFlag.West: + force.X -= thrust; + break; + default: + throw new ArgumentOutOfRangeException($"Attempted to apply thrust to shuttle {shuttleUid} along invalid dir {dir}."); + } - if (localVel.Length() >= maxVelocity.Length() && Vector2.Dot(totalForce, localVel) > 0f) - finalForce = Vector2.Zero; // burn would be faster if used as such + _thruster.EnableLinearThrustDirection(shuttle, dir); + var impulse = force * linearInput.Length(); + totalForce += impulse; + } - if (finalForce.Length() > properAccel.Length()) - finalForce = properAccel; // don't overshoot + var forceMul = frameTime * body.InvMass; - //Log.Info($"shuttle: maxVelocity {maxVelocity} totalForce {totalForce} finalForce {finalForce} forceMul {forceMul} properAccel {properAccel}"); + var localVel = (-shuttleNorthAngle).RotateVec(body.LinearVelocity); + var maxVelocity = ObtainMaxVel(localVel, shuttle); // max for current travel dir + var maxWishVelocity = ObtainMaxVel(totalForce, shuttle); + var properAccel = (maxWishVelocity - localVel) / forceMul; - finalForce = shuttleNorthAngle.RotateVec(finalForce); + var finalForce = Vector2Dot(totalForce, properAccel.Normalized()) * properAccel.Normalized(); - if (finalForce.Length() > 0f) - PhysicsSystem.ApplyForce(shuttleUid, finalForce, body: body); - } + if (localVel.Length() >= maxVelocity.Length() && Vector2.Dot(totalForce, localVel) > 0f) + finalForce = Vector2.Zero; // burn would be faster if used as such - if (MathHelper.CloseTo(angularInput, 0f)) - { - PhysicsSystem.SetSleepingAllowed(shuttleUid, body, true); + if (finalForce.Length() > properAccel.Length()) + finalForce = properAccel; // don't overshoot - if (brakeInput <= 0f) - _thruster.SetAngularThrust(shuttle, false); - } - else - { - PhysicsSystem.SetSleepingAllowed(shuttleUid, body, false); - var torque = shuttle.AngularThrust * -angularInput; + //Log.Info($"shuttle: maxVelocity {maxVelocity} totalForce {totalForce} finalForce {finalForce} forceMul {forceMul} properAccel {properAccel}"); - // Need to cap the velocity if 1 tick of input brings us over cap so we don't continuously - // edge onto the cap over and over. - var torqueMul = body.InvI * frameTime; + finalForce = shuttleNorthAngle.RotateVec(finalForce); - torque = Math.Clamp(torque, - (-ShuttleComponent.MaxAngularVelocity - body.AngularVelocity) / torqueMul, - (ShuttleComponent.MaxAngularVelocity - body.AngularVelocity) / torqueMul); + if (finalForce.Length() > 0f) + PhysicsSystem.ApplyForce(shuttleUid, finalForce, body: body); + } - if (!torque.Equals(0f)) - { - PhysicsSystem.ApplyTorque(shuttleUid, torque, body: body); - _thruster.SetAngularThrust(shuttle, true); - } - } + if (MathHelper.CloseTo(angularInput, 0f)) + { + PhysicsSystem.SetSleepingAllowed(shuttleUid, body, true); + + if (brakeInput <= 0f) + _thruster.SetAngularThrust(shuttle, false); } - } + else + { + PhysicsSystem.SetSleepingAllowed(shuttleUid, body, false); + var torque = shuttle.AngularThrust * -angularInput; - // .NET 8 seem to miscompile usage of Vector2.Dot above. This manual outline fixes it pending an upstream fix. - // See PR #24008 - [MethodImpl(MethodImplOptions.NoInlining)] - public static float Vector2Dot(Vector2 value1, Vector2 value2) - { - return Vector2.Dot(value1, value2); - } + // Need to cap the velocity if 1 tick of input brings us over cap so we don't continuously + // edge onto the cap over and over. + var torqueMul = body.InvI * frameTime; - private bool CanPilot(EntityUid shuttleUid) - { - return TryComp(shuttleUid, out var ftl) - && (ftl.State & (FTLState.Starting | FTLState.Travelling | FTLState.Arriving)) != 0x0 - || HasComp(shuttleUid); + torque = Math.Clamp(torque, + (-ShuttleComponent.MaxAngularVelocity - body.AngularVelocity) / torqueMul, + (ShuttleComponent.MaxAngularVelocity - body.AngularVelocity) / torqueMul); + + if (!torque.Equals(0f)) + { + PhysicsSystem.ApplyTorque(shuttleUid, torque, body: body); + _thruster.SetAngularThrust(shuttle, true); + } + } } + } + + // .NET 8 seem to miscompile usage of Vector2.Dot above. This manual outline fixes it pending an upstream fix. + // See PR #24008 + [MethodImpl(MethodImplOptions.NoInlining)] + public static float Vector2Dot(Vector2 value1, Vector2 value2) + { + return Vector2.Dot(value1, value2); + } + private bool CanPilot(EntityUid shuttleUid) + { + return TryComp(shuttleUid, out var ftl) + && (ftl.State & (FTLState.Starting | FTLState.Travelling | FTLState.Arriving)) != 0x0 + || HasComp(shuttleUid); } + } diff --git a/Content.Shared/Movement/Systems/SharedMoverController.cs b/Content.Shared/Movement/Systems/SharedMoverController.cs index c41db21b01e..472d56b1d69 100644 --- a/Content.Shared/Movement/Systems/SharedMoverController.cs +++ b/Content.Shared/Movement/Systems/SharedMoverController.cs @@ -24,492 +24,491 @@ using Robust.Shared.Utility; using PullableComponent = Content.Shared.Movement.Pulling.Components.PullableComponent; -namespace Content.Shared.Movement.Systems +namespace Content.Shared.Movement.Systems; + +/// +/// Handles player and NPC mob movement. +/// NPCs are handled server-side only. +/// +public abstract partial class SharedMoverController : VirtualController { + [Dependency] private readonly IConfigurationManager _configManager = default!; + [Dependency] protected readonly IGameTiming Timing = default!; + [Dependency] private readonly IMapManager _mapManager = default!; + [Dependency] private readonly ITileDefinitionManager _tileDefinitionManager = default!; + [Dependency] private readonly EntityLookupSystem _lookup = default!; + [Dependency] private readonly InventorySystem _inventory = default!; + [Dependency] private readonly MobStateSystem _mobState = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedContainerSystem _container = default!; + [Dependency] private readonly SharedMapSystem _mapSystem = default!; + [Dependency] private readonly SharedGravitySystem _gravity = default!; + [Dependency] protected readonly SharedPhysicsSystem Physics = default!; + [Dependency] private readonly SharedTransformSystem _transform = default!; + [Dependency] private readonly TagSystem _tags = default!; + + protected EntityQuery MoverQuery; + protected EntityQuery MobMoverQuery; + protected EntityQuery RelayTargetQuery; + protected EntityQuery ModifierQuery; + protected EntityQuery PhysicsQuery; + protected EntityQuery RelayQuery; + protected EntityQuery PullableQuery; + protected EntityQuery XformQuery; + protected EntityQuery CanMoveInAirQuery; + protected EntityQuery NoRotateQuery; + protected EntityQuery FootstepModifierQuery; + protected EntityQuery MapGridQuery; + + /// + /// + /// + private float _stopSpeed; + + private bool _relativeMovement; + /// - /// Handles player and NPC mob movement. - /// NPCs are handled server-side only. + /// Cache the mob movement calculation to re-use elsewhere. /// - public abstract partial class SharedMoverController : VirtualController + public Dictionary UsedMobMovement = new(); + + public override void Initialize() { - [Dependency] private readonly IConfigurationManager _configManager = default!; - [Dependency] protected readonly IGameTiming Timing = default!; - [Dependency] private readonly IMapManager _mapManager = default!; - [Dependency] private readonly ITileDefinitionManager _tileDefinitionManager = default!; - [Dependency] private readonly EntityLookupSystem _lookup = default!; - [Dependency] private readonly InventorySystem _inventory = default!; - [Dependency] private readonly MobStateSystem _mobState = default!; - [Dependency] private readonly SharedAudioSystem _audio = default!; - [Dependency] private readonly SharedContainerSystem _container = default!; - [Dependency] private readonly SharedMapSystem _mapSystem = default!; - [Dependency] private readonly SharedGravitySystem _gravity = default!; - [Dependency] protected readonly SharedPhysicsSystem Physics = default!; - [Dependency] private readonly SharedTransformSystem _transform = default!; - [Dependency] private readonly TagSystem _tags = default!; - - protected EntityQuery MoverQuery; - protected EntityQuery MobMoverQuery; - protected EntityQuery RelayTargetQuery; - protected EntityQuery ModifierQuery; - protected EntityQuery PhysicsQuery; - protected EntityQuery RelayQuery; - protected EntityQuery PullableQuery; - protected EntityQuery XformQuery; - protected EntityQuery CanMoveInAirQuery; - protected EntityQuery NoRotateQuery; - protected EntityQuery FootstepModifierQuery; - protected EntityQuery MapGridQuery; - - /// - /// - /// - private float _stopSpeed; - - private bool _relativeMovement; - - /// - /// Cache the mob movement calculation to re-use elsewhere. - /// - public Dictionary UsedMobMovement = new(); - - public override void Initialize() - { - base.Initialize(); - - MoverQuery = GetEntityQuery(); - MobMoverQuery = GetEntityQuery(); - ModifierQuery = GetEntityQuery(); - RelayTargetQuery = GetEntityQuery(); - PhysicsQuery = GetEntityQuery(); - RelayQuery = GetEntityQuery(); - PullableQuery = GetEntityQuery(); - XformQuery = GetEntityQuery(); - NoRotateQuery = GetEntityQuery(); - CanMoveInAirQuery = GetEntityQuery(); - FootstepModifierQuery = GetEntityQuery(); - MapGridQuery = GetEntityQuery(); - - InitializeInput(); - InitializeRelay(); - Subs.CVar(_configManager, CCVars.RelativeMovement, value => _relativeMovement = value, true); - Subs.CVar(_configManager, CCVars.StopSpeed, value => _stopSpeed = value, true); - UpdatesBefore.Add(typeof(TileFrictionController)); - } + base.Initialize(); + + MoverQuery = GetEntityQuery(); + MobMoverQuery = GetEntityQuery(); + ModifierQuery = GetEntityQuery(); + RelayTargetQuery = GetEntityQuery(); + PhysicsQuery = GetEntityQuery(); + RelayQuery = GetEntityQuery(); + PullableQuery = GetEntityQuery(); + XformQuery = GetEntityQuery(); + NoRotateQuery = GetEntityQuery(); + CanMoveInAirQuery = GetEntityQuery(); + FootstepModifierQuery = GetEntityQuery(); + MapGridQuery = GetEntityQuery(); + + InitializeInput(); + InitializeRelay(); + Subs.CVar(_configManager, CCVars.RelativeMovement, value => _relativeMovement = value, true); + Subs.CVar(_configManager, CCVars.StopSpeed, value => _stopSpeed = value, true); + UpdatesBefore.Add(typeof(TileFrictionController)); + } - public override void Shutdown() - { - base.Shutdown(); - ShutdownInput(); - } + public override void Shutdown() + { + base.Shutdown(); + ShutdownInput(); + } - public override void UpdateAfterSolve(bool prediction, float frameTime) - { - base.UpdateAfterSolve(prediction, frameTime); - UsedMobMovement.Clear(); - } + public override void UpdateAfterSolve(bool prediction, float frameTime) + { + base.UpdateAfterSolve(prediction, frameTime); + UsedMobMovement.Clear(); + } - /// - /// Movement while considering actionblockers, weightlessness, etc. - /// - protected void HandleMobMovement( - EntityUid uid, - InputMoverComponent mover, - EntityUid physicsUid, - PhysicsComponent physicsComponent, - TransformComponent xform, - float frameTime) + /// + /// Movement while considering actionblockers, weightlessness, etc. + /// + protected void HandleMobMovement( + EntityUid uid, + InputMoverComponent mover, + EntityUid physicsUid, + PhysicsComponent physicsComponent, + TransformComponent xform, + float frameTime) + { + var canMove = mover.CanMove; + if (RelayTargetQuery.TryGetComponent(uid, out var relayTarget)) { - var canMove = mover.CanMove; - if (RelayTargetQuery.TryGetComponent(uid, out var relayTarget)) + if (_mobState.IsIncapacitated(relayTarget.Source) || + TryComp(relayTarget.Source, out _) || + !MoverQuery.TryGetComponent(relayTarget.Source, out var relayedMover)) { - if (_mobState.IsIncapacitated(relayTarget.Source) || - TryComp(relayTarget.Source, out _) || - !MoverQuery.TryGetComponent(relayTarget.Source, out var relayedMover)) - { - canMove = false; - } - else - { - mover.RelativeEntity = relayedMover.RelativeEntity; - mover.RelativeRotation = relayedMover.RelativeRotation; - mover.TargetRelativeRotation = relayedMover.TargetRelativeRotation; - } + canMove = false; } - - // Update relative movement - if (mover.LerpTarget < Timing.CurTime) + else { - if (TryUpdateRelative(mover, xform)) - { - Dirty(uid, mover); - } + mover.RelativeEntity = relayedMover.RelativeEntity; + mover.RelativeRotation = relayedMover.RelativeRotation; + mover.TargetRelativeRotation = relayedMover.TargetRelativeRotation; } + } - LerpRotation(uid, mover, frameTime); - - if (!canMove - || physicsComponent.BodyStatus != BodyStatus.OnGround && !CanMoveInAirQuery.HasComponent(uid) - || PullableQuery.TryGetComponent(uid, out var pullable) && pullable.BeingPulled) + // Update relative movement + if (mover.LerpTarget < Timing.CurTime) + { + if (TryUpdateRelative(mover, xform)) { - UsedMobMovement[uid] = false; - return; + Dirty(uid, mover); } + } + LerpRotation(uid, mover, frameTime); - UsedMobMovement[uid] = true; - // Specifically don't use mover.Owner because that may be different to the actual physics body being moved. - var weightless = _gravity.IsWeightless(physicsUid, physicsComponent, xform); - var (walkDir, sprintDir) = GetVelocityInput(mover); - var touching = false; - - // Handle wall-pushes. - if (weightless) - { - if (xform.GridUid != null) - touching = true; + if (!canMove + || physicsComponent.BodyStatus != BodyStatus.OnGround && !CanMoveInAirQuery.HasComponent(uid) + || PullableQuery.TryGetComponent(uid, out var pullable) && pullable.BeingPulled) + { + UsedMobMovement[uid] = false; + return; + } - if (!touching) - { - var ev = new CanWeightlessMoveEvent(uid); - RaiseLocalEvent(uid, ref ev, true); - // No gravity: is our entity touching anything? - touching = ev.CanMove; - if (!touching && TryComp(uid, out var mobMover)) - touching |= IsAroundCollider(PhysicsSystem, xform, mobMover, physicsUid, physicsComponent); - } - } + UsedMobMovement[uid] = true; + // Specifically don't use mover.Owner because that may be different to the actual physics body being moved. + var weightless = _gravity.IsWeightless(physicsUid, physicsComponent, xform); + var (walkDir, sprintDir) = GetVelocityInput(mover); + var touching = false; - // Get current tile def for things like speed/friction mods - ContentTileDefinition? tileDef = null; + // Handle wall-pushes. + if (weightless) + { + if (xform.GridUid != null) + touching = true; - // Don't bother getting the tiledef here if we're weightless or in-air - // since no tile-based modifiers should be applying in that situation - if (MapGridQuery.TryComp(xform.GridUid, out var gridComp) - && _mapSystem.TryGetTileRef(xform.GridUid.Value, gridComp, xform.Coordinates, out var tile) - && !(weightless || physicsComponent.BodyStatus == BodyStatus.InAir)) + if (!touching) { - tileDef = (ContentTileDefinition) _tileDefinitionManager[tile.Tile.TypeId]; + var ev = new CanWeightlessMoveEvent(uid); + RaiseLocalEvent(uid, ref ev, true); + // No gravity: is our entity touching anything? + touching = ev.CanMove; + + if (!touching && TryComp(uid, out var mobMover)) + touching |= IsAroundCollider(PhysicsSystem, xform, mobMover, physicsUid, physicsComponent); } + } - // Regular movement. - // Target velocity. - // This is relative to the map / grid we're on. - var moveSpeedComponent = ModifierQuery.CompOrNull(uid); + // Get current tile def for things like speed/friction mods + ContentTileDefinition? tileDef = null; - var walkSpeed = moveSpeedComponent?.CurrentWalkSpeed ?? MovementSpeedModifierComponent.DefaultBaseWalkSpeed; - var sprintSpeed = moveSpeedComponent?.CurrentSprintSpeed ?? MovementSpeedModifierComponent.DefaultBaseSprintSpeed; + // Don't bother getting the tiledef here if we're weightless or in-air + // since no tile-based modifiers should be applying in that situation + if (MapGridQuery.TryComp(xform.GridUid, out var gridComp) + && _mapSystem.TryGetTileRef(xform.GridUid.Value, gridComp, xform.Coordinates, out var tile) + && !(weightless || physicsComponent.BodyStatus == BodyStatus.InAir)) + { + tileDef = (ContentTileDefinition) _tileDefinitionManager[tile.Tile.TypeId]; + } - var total = walkDir * walkSpeed + sprintDir * sprintSpeed; + // Regular movement. + // Target velocity. + // This is relative to the map / grid we're on. + var moveSpeedComponent = ModifierQuery.CompOrNull(uid); - var parentRotation = GetParentGridAngle(mover); - var worldTotal = _relativeMovement ? parentRotation.RotateVec(total) : total; + var walkSpeed = moveSpeedComponent?.CurrentWalkSpeed ?? MovementSpeedModifierComponent.DefaultBaseWalkSpeed; + var sprintSpeed = moveSpeedComponent?.CurrentSprintSpeed ?? MovementSpeedModifierComponent.DefaultBaseSprintSpeed; - DebugTools.Assert(MathHelper.CloseToPercent(total.Length(), worldTotal.Length())); + var total = walkDir * walkSpeed + sprintDir * sprintSpeed; - var velocity = physicsComponent.LinearVelocity; - float friction; - float weightlessModifier; - float accel; + var parentRotation = GetParentGridAngle(mover); + var worldTotal = _relativeMovement ? parentRotation.RotateVec(total) : total; - if (weightless) - { - if (gridComp == null && !MapGridQuery.HasComp(xform.GridUid)) - friction = moveSpeedComponent?.OffGridFriction ?? MovementSpeedModifierComponent.DefaultOffGridFriction; - else if (worldTotal != Vector2.Zero && touching) - friction = moveSpeedComponent?.WeightlessFriction ?? MovementSpeedModifierComponent.DefaultWeightlessFriction; - else - friction = moveSpeedComponent?.WeightlessFrictionNoInput ?? MovementSpeedModifierComponent.DefaultWeightlessFrictionNoInput; + DebugTools.Assert(MathHelper.CloseToPercent(total.Length(), worldTotal.Length())); + + var velocity = physicsComponent.LinearVelocity; + float friction; + float weightlessModifier; + float accel; + + if (weightless) + { + if (gridComp == null && !MapGridQuery.HasComp(xform.GridUid)) + friction = moveSpeedComponent?.OffGridFriction ?? MovementSpeedModifierComponent.DefaultOffGridFriction; + else if (worldTotal != Vector2.Zero && touching) + friction = moveSpeedComponent?.WeightlessFriction ?? MovementSpeedModifierComponent.DefaultWeightlessFriction; + else + friction = moveSpeedComponent?.WeightlessFrictionNoInput ?? MovementSpeedModifierComponent.DefaultWeightlessFrictionNoInput; - weightlessModifier = moveSpeedComponent?.WeightlessModifier ?? MovementSpeedModifierComponent.DefaultWeightlessModifier; - accel = moveSpeedComponent?.WeightlessAcceleration ?? MovementSpeedModifierComponent.DefaultWeightlessAcceleration; + weightlessModifier = moveSpeedComponent?.WeightlessModifier ?? MovementSpeedModifierComponent.DefaultWeightlessModifier; + accel = moveSpeedComponent?.WeightlessAcceleration ?? MovementSpeedModifierComponent.DefaultWeightlessAcceleration; + } + else + { + if (worldTotal != Vector2.Zero || moveSpeedComponent?.FrictionNoInput == null) + { + friction = tileDef?.MobFriction ?? moveSpeedComponent?.Friction ?? MovementSpeedModifierComponent.DefaultFriction; } else { - if (worldTotal != Vector2.Zero || moveSpeedComponent?.FrictionNoInput == null) - { - friction = tileDef?.MobFriction ?? moveSpeedComponent?.Friction ?? MovementSpeedModifierComponent.DefaultFriction; - } - else - { - friction = tileDef?.MobFrictionNoInput ?? moveSpeedComponent.FrictionNoInput ?? MovementSpeedModifierComponent.DefaultFrictionNoInput; - } - - weightlessModifier = 1f; - accel = tileDef?.MobAcceleration ?? moveSpeedComponent?.Acceleration ?? MovementSpeedModifierComponent.DefaultAcceleration; + friction = tileDef?.MobFrictionNoInput ?? moveSpeedComponent.FrictionNoInput ?? MovementSpeedModifierComponent.DefaultFrictionNoInput; } - var minimumFrictionSpeed = moveSpeedComponent?.MinimumFrictionSpeed ?? MovementSpeedModifierComponent.DefaultMinimumFrictionSpeed; - Friction(minimumFrictionSpeed, frameTime, friction, ref velocity); + weightlessModifier = 1f; + accel = tileDef?.MobAcceleration ?? moveSpeedComponent?.Acceleration ?? MovementSpeedModifierComponent.DefaultAcceleration; + } - if (worldTotal != Vector2.Zero) + var minimumFrictionSpeed = moveSpeedComponent?.MinimumFrictionSpeed ?? MovementSpeedModifierComponent.DefaultMinimumFrictionSpeed; + Friction(minimumFrictionSpeed, frameTime, friction, ref velocity); + + if (worldTotal != Vector2.Zero) + { + if (!NoRotateQuery.HasComponent(uid)) + { + // TODO apparently this results in a duplicate move event because "This should have its event run during + // island solver"??. So maybe SetRotation needs an argument to avoid raising an event? + var worldRot = _transform.GetWorldRotation(xform); + _transform.SetLocalRotation(xform, xform.LocalRotation + worldTotal.ToWorldAngle() - worldRot); + } + + if (!weightless && MobMoverQuery.TryGetComponent(uid, out var mobMover) && + TryGetSound(weightless, uid, mover, mobMover, xform, out var sound, tileDef: tileDef)) { - if (!NoRotateQuery.HasComponent(uid)) + var soundModifier = mover.Sprinting ? 3.5f : 1.5f; + + var audioParams = sound.Params + .WithVolume(sound.Params.Volume + soundModifier) + .WithVariation(sound.Params.Variation ?? mobMover.FootstepVariation); + + // If we're a relay target then predict the sound for all relays. + if (relayTarget != null) { - // TODO apparently this results in a duplicate move event because "This should have its event run during - // island solver"??. So maybe SetRotation needs an argument to avoid raising an event? - var worldRot = _transform.GetWorldRotation(xform); - _transform.SetLocalRotation(xform, xform.LocalRotation + worldTotal.ToWorldAngle() - worldRot); + _audio.PlayPredicted(sound, uid, relayTarget.Source, audioParams); } - - if (!weightless && MobMoverQuery.TryGetComponent(uid, out var mobMover) && - TryGetSound(weightless, uid, mover, mobMover, xform, out var sound, tileDef: tileDef)) + else { - var soundModifier = mover.Sprinting ? 3.5f : 1.5f; - - var audioParams = sound.Params - .WithVolume(sound.Params.Volume + soundModifier) - .WithVariation(sound.Params.Variation ?? mobMover.FootstepVariation); - - // If we're a relay target then predict the sound for all relays. - if (relayTarget != null) - { - _audio.PlayPredicted(sound, uid, relayTarget.Source, audioParams); - } - else - { - _audio.PlayPredicted(sound, uid, uid, audioParams); - } + _audio.PlayPredicted(sound, uid, uid, audioParams); } } + } - worldTotal *= weightlessModifier; + worldTotal *= weightlessModifier; - if (!weightless || touching) - Accelerate(ref velocity, in worldTotal, accel, frameTime); + if (!weightless || touching) + Accelerate(ref velocity, in worldTotal, accel, frameTime); - PhysicsSystem.SetLinearVelocity(physicsUid, velocity, body: physicsComponent); + PhysicsSystem.SetLinearVelocity(physicsUid, velocity, body: physicsComponent); - // Ensures that players do not spiiiiiiin - PhysicsSystem.SetAngularVelocity(physicsUid, 0, body: physicsComponent); - } + // Ensures that players do not spiiiiiiin + PhysicsSystem.SetAngularVelocity(physicsUid, 0, body: physicsComponent); + } - public void LerpRotation(EntityUid uid, InputMoverComponent mover, float frameTime) + public void LerpRotation(EntityUid uid, InputMoverComponent mover, float frameTime) + { + var angleDiff = Angle.ShortestDistance(mover.RelativeRotation, mover.TargetRelativeRotation); + + // if we've just traversed then lerp to our target rotation. + if (!angleDiff.EqualsApprox(Angle.Zero, 0.001)) { - var angleDiff = Angle.ShortestDistance(mover.RelativeRotation, mover.TargetRelativeRotation); + var adjustment = angleDiff * 5f * frameTime; + var minAdjustment = 0.01 * frameTime; - // if we've just traversed then lerp to our target rotation. - if (!angleDiff.EqualsApprox(Angle.Zero, 0.001)) + if (angleDiff < 0) { - var adjustment = angleDiff * 5f * frameTime; - var minAdjustment = 0.01 * frameTime; - - if (angleDiff < 0) - { - adjustment = Math.Min(adjustment, -minAdjustment); - adjustment = Math.Clamp(adjustment, angleDiff, -angleDiff); - } - else - { - adjustment = Math.Max(adjustment, minAdjustment); - adjustment = Math.Clamp(adjustment, -angleDiff, angleDiff); - } - - mover.RelativeRotation += adjustment; - mover.RelativeRotation.FlipPositive(); - Dirty(uid, mover); + adjustment = Math.Min(adjustment, -minAdjustment); + adjustment = Math.Clamp(adjustment, angleDiff, -angleDiff); } - else if (!angleDiff.Equals(Angle.Zero)) + else { - mover.TargetRelativeRotation.FlipPositive(); - mover.RelativeRotation = mover.TargetRelativeRotation; - Dirty(uid, mover); + adjustment = Math.Max(adjustment, minAdjustment); + adjustment = Math.Clamp(adjustment, -angleDiff, angleDiff); } - } - private void Friction(float minimumFrictionSpeed, float frameTime, float friction, ref Vector2 velocity) + mover.RelativeRotation += adjustment; + mover.RelativeRotation.FlipPositive(); + Dirty(uid, mover); + } + else if (!angleDiff.Equals(Angle.Zero)) { - var speed = velocity.Length(); + mover.TargetRelativeRotation.FlipPositive(); + mover.RelativeRotation = mover.TargetRelativeRotation; + Dirty(uid, mover); + } + } - if (speed < minimumFrictionSpeed) - return; + private void Friction(float minimumFrictionSpeed, float frameTime, float friction, ref Vector2 velocity) + { + var speed = velocity.Length(); - var drop = 0f; + if (speed < minimumFrictionSpeed) + return; - var control = MathF.Max(_stopSpeed, speed); - drop += control * friction * frameTime; + var drop = 0f; - var newSpeed = MathF.Max(0f, speed - drop); + var control = MathF.Max(_stopSpeed, speed); + drop += control * friction * frameTime; - if (newSpeed.Equals(speed)) - return; + var newSpeed = MathF.Max(0f, speed - drop); - newSpeed /= speed; - velocity *= newSpeed; - } + if (newSpeed.Equals(speed)) + return; - private void Accelerate(ref Vector2 currentVelocity, in Vector2 velocity, float accel, float frameTime) - { - var wishDir = velocity != Vector2.Zero ? velocity.Normalized() : Vector2.Zero; - var wishSpeed = velocity.Length(); + newSpeed /= speed; + velocity *= newSpeed; + } - var currentSpeed = Vector2.Dot(currentVelocity, wishDir); - var addSpeed = wishSpeed - currentSpeed; + private void Accelerate(ref Vector2 currentVelocity, in Vector2 velocity, float accel, float frameTime) + { + var wishDir = velocity != Vector2.Zero ? velocity.Normalized() : Vector2.Zero; + var wishSpeed = velocity.Length(); - if (addSpeed <= 0f) - return; + var currentSpeed = Vector2.Dot(currentVelocity, wishDir); + var addSpeed = wishSpeed - currentSpeed; - var accelSpeed = accel * frameTime * wishSpeed; - accelSpeed = MathF.Min(accelSpeed, addSpeed); + if (addSpeed <= 0f) + return; - currentVelocity += wishDir * accelSpeed; - } + var accelSpeed = accel * frameTime * wishSpeed; + accelSpeed = MathF.Min(accelSpeed, addSpeed); - public bool UseMobMovement(EntityUid uid) - { - return UsedMobMovement.TryGetValue(uid, out var used) && used; - } + currentVelocity += wishDir * accelSpeed; + } - /// - /// Used for weightlessness to determine if we are near a wall. - /// - private bool IsAroundCollider(SharedPhysicsSystem broadPhaseSystem, TransformComponent transform, MobMoverComponent mover, EntityUid physicsUid, PhysicsComponent collider) - { - var enlargedAABB = _lookup.GetWorldAABB(physicsUid, transform).Enlarged(mover.GrabRangeVV); + public bool UseMobMovement(EntityUid uid) + { + return UsedMobMovement.TryGetValue(uid, out var used) && used; + } - foreach (var otherCollider in broadPhaseSystem.GetCollidingEntities(transform.MapID, enlargedAABB)) - { - if (otherCollider == collider) - continue; // Don't try to push off of yourself! - - // Only allow pushing off of anchored things that have collision. - if (otherCollider.BodyType != BodyType.Static || - !otherCollider.CanCollide || - ((collider.CollisionMask & otherCollider.CollisionLayer) == 0 && - (otherCollider.CollisionMask & collider.CollisionLayer) == 0) || - (TryComp(otherCollider.Owner, out PullableComponent? pullable) && pullable.BeingPulled)) - { - continue; - } + /// + /// Used for weightlessness to determine if we are near a wall. + /// + private bool IsAroundCollider(SharedPhysicsSystem broadPhaseSystem, TransformComponent transform, MobMoverComponent mover, EntityUid physicsUid, PhysicsComponent collider) + { + var enlargedAABB = _lookup.GetWorldAABB(physicsUid, transform).Enlarged(mover.GrabRangeVV); - return true; + foreach (var otherCollider in broadPhaseSystem.GetCollidingEntities(transform.MapID, enlargedAABB)) + { + if (otherCollider == collider) + continue; // Don't try to push off of yourself! + + // Only allow pushing off of anchored things that have collision. + if (otherCollider.BodyType != BodyType.Static || + !otherCollider.CanCollide || + ((collider.CollisionMask & otherCollider.CollisionLayer) == 0 && + (otherCollider.CollisionMask & collider.CollisionLayer) == 0) || + (TryComp(otherCollider.Owner, out PullableComponent? pullable) && pullable.BeingPulled)) + { + continue; } - return false; + return true; } - protected abstract bool CanSound(); + return false; + } + + protected abstract bool CanSound(); - private bool TryGetSound( - bool weightless, - EntityUid uid, - InputMoverComponent mover, - MobMoverComponent mobMover, - TransformComponent xform, - [NotNullWhen(true)] out SoundSpecifier? sound, - ContentTileDefinition? tileDef = null) - { - sound = null; + private bool TryGetSound( + bool weightless, + EntityUid uid, + InputMoverComponent mover, + MobMoverComponent mobMover, + TransformComponent xform, + [NotNullWhen(true)] out SoundSpecifier? sound, + ContentTileDefinition? tileDef = null) + { + sound = null; - if (!CanSound() || !_tags.HasTag(uid, "FootstepSound")) - return false; + if (!CanSound() || !_tags.HasTag(uid, "FootstepSound")) + return false; - var coordinates = xform.Coordinates; - var distanceNeeded = mover.Sprinting - ? mobMover.StepSoundMoveDistanceRunning - : mobMover.StepSoundMoveDistanceWalking; + var coordinates = xform.Coordinates; + var distanceNeeded = mover.Sprinting + ? mobMover.StepSoundMoveDistanceRunning + : mobMover.StepSoundMoveDistanceWalking; - // Handle footsteps. - if (!weightless) + // Handle footsteps. + if (!weightless) + { + // Can happen when teleporting between grids. + if (!coordinates.TryDistance(EntityManager, mobMover.LastPosition, out var distance) || + distance > distanceNeeded) { - // Can happen when teleporting between grids. - if (!coordinates.TryDistance(EntityManager, mobMover.LastPosition, out var distance) || - distance > distanceNeeded) - { - mobMover.StepSoundDistance = distanceNeeded; - } - else - { - mobMover.StepSoundDistance += distance; - } + mobMover.StepSoundDistance = distanceNeeded; } else { - // In space no one can hear you squeak - return false; + mobMover.StepSoundDistance += distance; } + } + else + { + // In space no one can hear you squeak + return false; + } - mobMover.LastPosition = coordinates; + mobMover.LastPosition = coordinates; - if (mobMover.StepSoundDistance < distanceNeeded) - return false; + if (mobMover.StepSoundDistance < distanceNeeded) + return false; - mobMover.StepSoundDistance -= distanceNeeded; + mobMover.StepSoundDistance -= distanceNeeded; - if (FootstepModifierQuery.TryComp(uid, out var moverModifier)) - { - sound = moverModifier.FootstepSoundCollection; - return true; - } + if (FootstepModifierQuery.TryComp(uid, out var moverModifier)) + { + sound = moverModifier.FootstepSoundCollection; + return true; + } - if (_inventory.TryGetSlotEntity(uid, "shoes", out var shoes) && - FootstepModifierQuery.TryComp(shoes, out var modifier)) + if (_inventory.TryGetSlotEntity(uid, "shoes", out var shoes) && + FootstepModifierQuery.TryComp(shoes, out var modifier)) + { + sound = modifier.FootstepSoundCollection; + return true; + } + + return TryGetFootstepSound(uid, xform, shoes != null, out sound, tileDef: tileDef); + } + + private bool TryGetFootstepSound( + EntityUid uid, + TransformComponent xform, + bool haveShoes, + [NotNullWhen(true)] out SoundSpecifier? sound, + ContentTileDefinition? tileDef = null) + { + sound = null; + + // Fallback to the map? + if (!MapGridQuery.TryComp(xform.GridUid, out var grid)) + { + if (FootstepModifierQuery.TryComp(xform.MapUid, out var modifier)) { sound = modifier.FootstepSoundCollection; return true; } - return TryGetFootstepSound(uid, xform, shoes != null, out sound, tileDef: tileDef); + return false; } - private bool TryGetFootstepSound( - EntityUid uid, - TransformComponent xform, - bool haveShoes, - [NotNullWhen(true)] out SoundSpecifier? sound, - ContentTileDefinition? tileDef = null) - { - sound = null; + var position = grid.LocalToTile(xform.Coordinates); + var soundEv = new GetFootstepSoundEvent(uid); - // Fallback to the map? - if (!MapGridQuery.TryComp(xform.GridUid, out var grid)) - { - if (FootstepModifierQuery.TryComp(xform.MapUid, out var modifier)) - { - sound = modifier.FootstepSoundCollection; - return true; - } - - return false; - } - - var position = grid.LocalToTile(xform.Coordinates); - var soundEv = new GetFootstepSoundEvent(uid); + // If the coordinates have a FootstepModifier component + // i.e. component that emit sound on footsteps emit that sound + var anchored = grid.GetAnchoredEntitiesEnumerator(position); - // If the coordinates have a FootstepModifier component - // i.e. component that emit sound on footsteps emit that sound - var anchored = grid.GetAnchoredEntitiesEnumerator(position); + while (anchored.MoveNext(out var maybeFootstep)) + { + RaiseLocalEvent(maybeFootstep.Value, ref soundEv); - while (anchored.MoveNext(out var maybeFootstep)) + if (soundEv.Sound != null) { - RaiseLocalEvent(maybeFootstep.Value, ref soundEv); - - if (soundEv.Sound != null) - { - sound = soundEv.Sound; - return true; - } - - if (FootstepModifierQuery.TryComp(maybeFootstep, out var footstep)) - { - sound = footstep.FootstepSoundCollection; - return true; - } + sound = soundEv.Sound; + return true; } - // Walking on a tile. - // Tile def might have been passed in already from previous methods, so use that - // if we have it - if (tileDef == null && grid.TryGetTileRef(position, out var tileRef)) + if (FootstepModifierQuery.TryComp(maybeFootstep, out var footstep)) { - tileDef = (ContentTileDefinition) _tileDefinitionManager[tileRef.Tile.TypeId]; + sound = footstep.FootstepSoundCollection; + return true; } + } - if (tileDef == null) - return false; - - sound = haveShoes ? tileDef.FootstepSounds : tileDef.BarestepSounds; - return sound != null; + // Walking on a tile. + // Tile def might have been passed in already from previous methods, so use that + // if we have it + if (tileDef == null && grid.TryGetTileRef(position, out var tileRef)) + { + tileDef = (ContentTileDefinition) _tileDefinitionManager[tileRef.Tile.TypeId]; } + + if (tileDef == null) + return false; + + sound = haveShoes ? tileDef.FootstepSounds : tileDef.BarestepSounds; + return sound != null; } } From 1d997d6e46785042ab984ae0454e97ea664176fd Mon Sep 17 00:00:00 2001 From: slarticodefast <161409025+slarticodefast@users.noreply.github.com> Date: Fri, 13 Sep 2024 13:25:53 +0200 Subject: [PATCH 010/138] fix missing circuitboard recipes (#32092) * fix missing circuitboard recipes * and another one --- Resources/Prototypes/Recipes/Lathes/electronics.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Resources/Prototypes/Recipes/Lathes/electronics.yml b/Resources/Prototypes/Recipes/Lathes/electronics.yml index 67651dd3732..818ba0fe374 100644 --- a/Resources/Prototypes/Recipes/Lathes/electronics.yml +++ b/Resources/Prototypes/Recipes/Lathes/electronics.yml @@ -166,6 +166,7 @@ - type: latheRecipe parent: BaseGoldCircuitboardRecipe id: ChemMasterMachineCircuitboard + result: ChemMasterMachineCircuitboard - type: latheRecipe parent: BaseGoldCircuitboardRecipe @@ -431,6 +432,7 @@ - type: latheRecipe parent: BaseCircuitboardRecipe id: MicrowaveMachineCircuitboard + result: MicrowaveMachineCircuitboard - type: latheRecipe parent: BaseCircuitboardRecipe @@ -540,6 +542,7 @@ - type: latheRecipe parent: BaseGoldCircuitboardRecipe id: MiniGravityGeneratorCircuitboard + result: MiniGravityGeneratorCircuitboard - type: latheRecipe parent: BaseCircuitboardRecipe From b6ca604a661e2b98ed9b3e9a8f5ce88a7cd49cfa Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Fri, 13 Sep 2024 15:58:02 +0200 Subject: [PATCH 011/138] Fix replay load error screens (#32115) If an error occurs while loading a replay, it's *supposed* to show a popup "hey do you wanna continue with error tolerance", and it does do this. But because of spaghetti in the replay state code, it also immediately tries to reload the replay without input, as a consequence of trying to reset to the game's default state. Now the replay load system has a proper game state for "replay load failed", with nice presentation and explicit formatting and 10% less italian cuisine. --- .../Replay/ContentReplayPlaybackManager.cs | 48 ++++++++----------- .../Replay/UI/Loading/ReplayLoadingFailed.cs | 36 ++++++++++++++ .../Loading/ReplayLoadingFailedControl.xaml | 14 ++++++ .../ReplayLoadingFailedControl.xaml.cs | 44 +++++++++++++++++ Resources/Locale/en-US/replays/replays.ftl | 1 + 5 files changed, 114 insertions(+), 29 deletions(-) create mode 100644 Content.Client/Replay/UI/Loading/ReplayLoadingFailed.cs create mode 100644 Content.Client/Replay/UI/Loading/ReplayLoadingFailedControl.xaml create mode 100644 Content.Client/Replay/UI/Loading/ReplayLoadingFailedControl.xaml.cs diff --git a/Content.Client/Replay/ContentReplayPlaybackManager.cs b/Content.Client/Replay/ContentReplayPlaybackManager.cs index f90731bfa75..b96eae44e9d 100644 --- a/Content.Client/Replay/ContentReplayPlaybackManager.cs +++ b/Content.Client/Replay/ContentReplayPlaybackManager.cs @@ -1,10 +1,8 @@ -using System.IO.Compression; using Content.Client.Administration.Managers; using Content.Client.Launcher; using Content.Client.MainMenu; using Content.Client.Replay.Spectator; using Content.Client.Replay.UI.Loading; -using Content.Client.Stylesheets; using Content.Client.UserInterface.Systems.Chat; using Content.Shared.Chat; using Content.Shared.Effects; @@ -26,8 +24,6 @@ using Robust.Client.State; using Robust.Client.Timing; using Robust.Client.UserInterface; -using Robust.Client.UserInterface.Controls; -using Robust.Client.UserInterface.CustomControls; using Robust.Shared; using Robust.Shared.Configuration; using Robust.Shared.ContentPack; @@ -60,7 +56,7 @@ public sealed class ContentReplayPlaybackManager public bool IsScreenshotMode = false; private bool _initialized; - + /// /// Most recently loaded file, for re-attempting the load with error tolerance. /// Required because the zip reader auto-disposes and I'm too lazy to change it so that @@ -96,32 +92,17 @@ private void OnFinishedLoading(Exception? exception) return; } - ReturnToDefaultState(); - - // Show a popup window with the error message - var text = Loc.GetString("replay-loading-failed", ("reason", exception)); - var box = new BoxContainer - { - Orientation = BoxContainer.LayoutOrientation.Vertical, - Children = {new Label {Text = text}} - }; + if (_client.RunLevel == ClientRunLevel.SinglePlayerGame) + _client.StopSinglePlayer(); - var popup = new DefaultWindow { Title = "Error!" }; - popup.Contents.AddChild(box); + Action? retryAction = null; + Action? cancelAction = null; - // Add button for attempting to re-load the replay while ignoring some errors. - if (!_cfg.GetCVar(CVars.ReplayIgnoreErrors) && LastLoad is {} last) + if (!_cfg.GetCVar(CVars.ReplayIgnoreErrors) && LastLoad is { } last) { - var button = new Button - { - Text = Loc.GetString("replay-loading-retry"), - StyleClasses = { StyleBase.ButtonCaution } - }; - - button.OnPressed += _ => + retryAction = () => { _cfg.SetCVar(CVars.ReplayIgnoreErrors, true); - popup.Dispose(); IReplayFileReader reader = last.Zip == null ? new ReplayFileReaderResources(_resMan, last.Folder) @@ -129,11 +110,20 @@ private void OnFinishedLoading(Exception? exception) _loadMan.LoadAndStartReplay(reader); }; - - box.AddChild(button); } - popup.OpenCentered(); + // If we have an explicit menu to get back to (e.g. replay browser UI), show a cancel button. + if (DefaultState != null) + { + cancelAction = () => + { + _stateMan.RequestStateChange(DefaultState); + }; + } + + // Switch to a new game state to present the error and cancel/retry options. + var state = _stateMan.RequestStateChange(); + state.SetData(exception, cancelAction, retryAction); } public void ReturnToDefaultState() diff --git a/Content.Client/Replay/UI/Loading/ReplayLoadingFailed.cs b/Content.Client/Replay/UI/Loading/ReplayLoadingFailed.cs new file mode 100644 index 00000000000..223895eb29c --- /dev/null +++ b/Content.Client/Replay/UI/Loading/ReplayLoadingFailed.cs @@ -0,0 +1,36 @@ +using Content.Client.Stylesheets; +using Robust.Client.State; +using Robust.Client.UserInterface; +using Robust.Shared.Utility; + +namespace Content.Client.Replay.UI.Loading; + +/// +/// State used to display an error message if a replay failed to load. +/// +/// +/// +public sealed class ReplayLoadingFailed : State +{ + [Dependency] private readonly IStylesheetManager _stylesheetManager = default!; + [Dependency] private readonly IUserInterfaceManager _userInterface = default!; + + private ReplayLoadingFailedControl? _control; + + public void SetData(Exception exception, Action? cancelPressed, Action? retryPressed) + { + DebugTools.Assert(_control != null); + _control.SetData(exception, cancelPressed, retryPressed); + } + + protected override void Startup() + { + _control = new ReplayLoadingFailedControl(_stylesheetManager); + _userInterface.StateRoot.AddChild(_control); + } + + protected override void Shutdown() + { + _control?.Orphan(); + } +} diff --git a/Content.Client/Replay/UI/Loading/ReplayLoadingFailedControl.xaml b/Content.Client/Replay/UI/Loading/ReplayLoadingFailedControl.xaml new file mode 100644 index 00000000000..5f77a66e535 --- /dev/null +++ b/Content.Client/Replay/UI/Loading/ReplayLoadingFailedControl.xaml @@ -0,0 +1,14 @@ + + + + + + + + + [DataField] - public List> Tags { get; set; } = new(); + public List> Tags { get; set; } = new(); } diff --git a/Resources/Locale/en-US/flavors/flavor-profiles.ftl b/Resources/Locale/en-US/flavors/flavor-profiles.ftl index f56a6c36b8b..3e7cde8449a 100644 --- a/Resources/Locale/en-US/flavors/flavor-profiles.ftl +++ b/Resources/Locale/en-US/flavors/flavor-profiles.ftl @@ -174,6 +174,9 @@ flavor-complex-violets = like violets flavor-complex-pyrotton = like a burning mouth flavor-complex-mothballs = like mothballs flavor-complex-paint-thinner = like paint thinner +flavor-complex-numbing-tranquility = like numbing tranquility +flavor-complex-true-nature = like the true nature of reality +flavor-complex-false-meat = not entirely unlike meat flavor-complex-paper = like mushy pulp flavor-complex-compressed-meat = like compressed meat diff --git a/Resources/Locale/en-US/nutrition/components/food-sequence.ftl b/Resources/Locale/en-US/nutrition/components/food-sequence.ftl index 766145093e2..97dd7ffcc6a 100644 --- a/Resources/Locale/en-US/nutrition/components/food-sequence.ftl +++ b/Resources/Locale/en-US/nutrition/components/food-sequence.ftl @@ -14,6 +14,7 @@ food-sequence-content-salami = salami food-sequence-content-slime = slime food-sequence-content-clown = clown food-sequence-content-pea = pea +food-sequence-content-world-pea = world pea food-sequence-content-bungo = bungo food-sequence-content-banana = banana food-sequence-content-mimana = mimana @@ -64,6 +65,7 @@ food-sequence-content-glasstle = glasstle food-sequence-content-gatfruit = gatfruit food-sequence-content-koibean = koibean food-sequence-content-watermelon = watermelon +food-sequence-content-holymelon = holymelon food-sequence-content-cannabis = cannabis food-sequence-content-rainbow-cannabis = rainbow cannabis food-sequence-content-tobacco = tobacco @@ -71,7 +73,7 @@ food-sequence-content-hamster = hamster food-sequence-content-suppermatter = suppermatter food-sequence-content-capfruit = capfruit food-sequence-content-berries = berries -food-sequence-content-spacemans-trumpet = spacemans trupmet +food-sequence-content-spacemans-trumpet = spaceman's trupmet food-sequence-content-cherry = cherry food-sequence-content-snail = snail @@ -106,6 +108,7 @@ food-sequence-burger-content-rice = rice food-sequence-burger-content-soy = soy food-sequence-burger-content-koibean = koi food-sequence-burger-content-watermelon = water +food-sequence-burger-content-holymelon = holy food-sequence-burger-content-cannabis = funny food-sequence-burger-content-rainbow-cannabis = FUNNY food-sequence-burger-content-tobacco = tobaco @@ -113,6 +116,8 @@ food-sequence-burger-content-suppermatter = supper food-sequence-burger-content-hamster = hams food-sequence-burger-content-berries = berri food-sequence-burger-content-spacemans-trumpet = spacetrump +food-sequence-burger-content-extradimensional-orange = 3d +food-sequence-burger-content-world-pea = peace # TACO diff --git a/Resources/Locale/en-US/seeds/seeds.ftl b/Resources/Locale/en-US/seeds/seeds.ftl index 138d3c9914d..c8d524ba1d7 100644 --- a/Resources/Locale/en-US/seeds/seeds.ftl +++ b/Resources/Locale/en-US/seeds/seeds.ftl @@ -6,6 +6,8 @@ seeds-noun-spores = spores # Seeds seeds-wheat-name = wheat seeds-wheat-display-name = wheat stalks +seeds-meatwheat-name = meatwheat +seeds-meatwheat-display-name = meatwheat stalks seeds-oat-name = oat seeds-oat-display-name = oat stalks seeds-banana-name = banana @@ -26,6 +28,8 @@ seeds-lime-name = lime seeds-lime-display-name = lime trees seeds-orange-name = orange seeds-orange-display-name = orange trees +seeds-extradimensionalorange-name = extradimensional orange +seeds-extradimensionalorange-display-name = extradimensional orange trees seeds-pineapple-name = pineapple seeds-pineapple-display-name = pineapple plant seeds-potato-name = potato @@ -109,7 +113,9 @@ seeds-spacemans-trumpet-display-name = spaceman's trumpet plant seeds-koibean-name = koibeans seeds-koibean-display-name = koibean plant seeds-watermelon-name = watermelon -seeds-watermelon-display-name = watermelon plant +seeds-watermelon-display-name = watermelon vines +seeds-holymelon-name = holymelon +seeds-holymelon-display-name = holymelon vines seeds-grape-name = grape seeds-grape-display-name = grape plant seeds-cocoa-name = cocoa @@ -118,8 +124,10 @@ seeds-berries-name = berries seeds-berries-display-name = berry bush seeds-bungo-name = bungo seeds-bungo-display-name = bungo plant -seeds-pea-name = pea +seeds-pea-name = peas seeds-pea-display-name = pea vines +seeds-worldpea-name = world peas +seeds-worldpea-display-name = world pea vines seeds-pumpkin-name = pumpkin seeds-pumpkin-display-name = pumpkins seeds-blue-pumpkin-name = blue pumpkin diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml index 0ad425c7102..000f21db3f4 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml @@ -504,6 +504,9 @@ id: FoodMeatWheat description: This doesn't look like meat, but your standards aren't that high to begin with. components: + - type: FlavorProfile + flavors: + - falsemeat - type: Sprite state: clump - type: SolutionContainerManager @@ -796,8 +799,8 @@ node: bacon - type: FoodSequenceElement entries: - Burger: MeatBecon - Taco: MeatBecon + Burger: MeatBacon + Taco: MeatBacon - type: entity name: cooked bear diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/produce.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/produce.yml index 15af78e78fd..42fd0967ff1 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/produce.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/produce.yml @@ -56,6 +56,28 @@ tags: - Wheat +- type: entity + name: meatwheat bushel + description: Some blood-drenched wheat stalks. You can crush them into what passes for meat if you squint hard enough. + id: MeatwheatBushel + parent: ProduceBase + components: + - type: Sprite + sprite: Objects/Specific/Hydroponics/meatwheat.rsi + - type: SolutionContainerManager + solutions: + food: + reagents: + - ReagentId: UncookedAnimalProteins + Quantity: 10 + - type: SpawnItemsOnUse + items: + - id: FoodMeatWheat + sound: + path: /Audio/Voice/Slime/slime_squish.ogg + - type: Produce + seedId: meatwheat + - type: entity name: oat bushel description: Eat oats, do squats. @@ -652,6 +674,47 @@ Burger: Orange Taco: Orange +- type: entity + name: extradimensional orange + parent: FoodProduceBase + id: FoodExtradimensionalOrange + description: You can hardly wrap your head around this thing. + components: + - type: FlavorProfile + flavors: + - truenature + - type: SolutionContainerManager + solutions: + food: + maxVol: 14 + reagents: + - ReagentId: Haloperidol + Quantity: 5 + - ReagentId: Nutriment + Quantity: 5 + - ReagentId: Vitamin + Quantity: 4 + - type: Sprite + sprite: Objects/Specific/Hydroponics/extradimensional_orange.rsi + scale: 0.5,0.5 + - type: Produce + seedId: extradimensionalOrange + - type: PotencyVisuals + minimumScale: 0.5 # reduce this in size because the sprite is way too big + maximumScale: 1 + - type: Extractable + juiceSolution: + reagents: + - ReagentId: JuiceOrange + Quantity: 10 + - type: Tag + tags: + - Fruit + - type: FoodSequenceElement + entries: + Burger: ExtradimensionalOrangeBurger + Taco: ExtradimensionalOrange + - type: entity name: pineapple parent: FoodProduceBase @@ -1970,6 +2033,105 @@ Taco: WatermelonSlice Skewer: WatermelonSliceSkewer +- type: entity + name: holymelon + parent: [FoodProduceBase, ItemHeftyBase] + id: FoodHolymelon + description: The water within this melon has been blessed by some deity that's particularly fond of watermelon. + components: + - type: Item + size: Small + - type: FlavorProfile + flavors: + - holy + - watermelon + - type: SolutionContainerManager + solutions: + food: + maxVol: 25 + reagents: + - ReagentId: Nutriment + Quantity: 10 + - ReagentId: Vitamin + Quantity: 5 + - ReagentId: Holywater + Quantity: 10 + - type: Sprite + sprite: Objects/Specific/Hydroponics/holymelon.rsi + - type: Produce + seedId: watermelon + - type: Extractable + juiceSolution: + reagents: + - ReagentId: Wine + Quantity: 20 + - type: Damageable + damageContainer: Biological + - type: DamageOnHighSpeedImpact + minimumSpeed: 0.1 + damage: + types: + Blunt: 1 + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 1 + behaviors: + - !type:PlaySoundBehavior + sound: + collection: desecration + - !type:SpillBehavior + solution: food + - !type:DoActsBehavior + acts: [ "Destruction" ] + - type: SliceableFood + count: 5 + slice: FoodHolymelonSlice + - type: Tag + tags: + - Fruit + +- type: entity + name: holymelon slice + parent: ProduceSliceBase + id: FoodHolymelonSlice + description: Juicy golden and red slice. + components: + - type: Item + size: Tiny + - type: FlavorProfile + flavors: + - holy + - watermelon + - type: Sprite + sprite: Objects/Specific/Hydroponics/holymelon.rsi + - type: SolutionContainerManager + solutions: + food: + maxVol: 5 + reagents: + - ReagentId: Nutriment + Quantity: 2 + - ReagentId: Vitamin + Quantity: 1 + - ReagentId: Holywater + Quantity: 2 + - type: Extractable + juiceSolution: + reagents: + - ReagentId: Wine + Quantity: 4 + - type: Tag + tags: + - Fruit + - Slice + - type: FoodSequenceElement + entries: + Burger: HolymelonSliceBurger + Taco: HolymelonSlice + Skewer: HolymelonSliceSkewer + - type: entity name: grapes parent: FoodProduceBase @@ -2132,6 +2294,38 @@ Taco: Pea Burger: Pea +- type: entity + parent: FoodProduceBase + id: FoodWorldPeas + name: cluster of world peas + description: It's rumored to bring peace to any who consume it. + components: + - type: FlavorProfile + flavors: + - numbingtranquility + - type: SolutionContainerManager + solutions: + food: + maxVol: 8 + reagents: + - ReagentId: Happiness + Quantity: 3 + - ReagentId: Nutriment + Quantity: 3 + - ReagentId: Pax + Quantity: 2 + - type: Sprite + sprite: Objects/Specific/Hydroponics/world_pea.rsi + - type: Produce + seedId: worldPea + - type: Tag + tags: + - Vegetable + - type: FoodSequenceElement + entries: + Taco: WorldPea + Burger: WorldPeaBurger + - type: entity name: pumpkin parent: FoodProduceBase diff --git a/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/seeds.yml b/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/seeds.yml index 56692f13cdc..6015a8bf013 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/seeds.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/seeds.yml @@ -22,6 +22,17 @@ - type: Sprite sprite: Objects/Specific/Hydroponics/wheat.rsi +- type: entity + parent: SeedBase + name: packet of meatwheat seeds + description: "If you ever wanted to drive a vegetarian to insanity, here's how." + id: MeatwheatSeeds + components: + - type: Seed + seedId: meatwheat + - type: Sprite + sprite: Objects/Specific/Hydroponics/meatwheat.rsi + - type: entity parent: SeedBase name: packet of oat seeds @@ -133,6 +144,17 @@ - type: Sprite sprite: Objects/Specific/Hydroponics/orange.rsi +- type: entity + parent: SeedBase + name: packet of extradimensional orange seeds + description: "Polygonal seeds." + id: ExtradimensionalOrangeSeeds + components: + - type: Seed + seedId: extradimensionalOrange + - type: Sprite + sprite: Objects/Specific/Hydroponics/extradimensional_orange.rsi + - type: entity parent: SeedBase name: packet of pineapple seeds @@ -562,6 +584,16 @@ - type: Sprite sprite: Objects/Specific/Hydroponics/watermelon.rsi +- type: entity + parent: SeedBase + name: packet of holymelon seeds + id: HolymelonSeeds + components: + - type: Seed + seedId: holymelon + - type: Sprite + sprite: Objects/Specific/Hydroponics/holymelon.rsi + - type: entity parent: SeedBase name: packet of grape seeds @@ -614,6 +646,17 @@ - type: Sprite sprite: Objects/Specific/Hydroponics/pea.rsi +- type: entity + parent: SeedBase + id: WorldPeaSeeds + name: packet of world pea seeds + description: "These rather large seeds give off a soothing blue glow." + components: + - type: Seed + seedId: worldPea + - type: Sprite + sprite: Objects/Specific/Hydroponics/world_pea.rsi + - type: entity parent: SeedBase name: packet of pumpkin seeds diff --git a/Resources/Prototypes/Flavors/flavors.yml b/Resources/Prototypes/Flavors/flavors.yml index c500229507b..3f536c871ae 100644 --- a/Resources/Prototypes/Flavors/flavors.yml +++ b/Resources/Prototypes/Flavors/flavors.yml @@ -1093,7 +1093,7 @@ id: bluepumpkin flavorType: Complex description: flavor-complex-blue-pumpkin - + - type: flavor id: violets flavorType: Complex @@ -1114,6 +1114,21 @@ flavorType: Complex description: flavor-complex-paint-thinner +- type: flavor + id: numbingtranquility + flavorType: Complex + description: flavor-complex-numbing-tranquility + +- type: flavor + id: truenature + flavorType: Complex + description: flavor-complex-true-nature + +- type: flavor + id: falsemeat + flavorType: Complex + description: flavor-complex-false-meat + - type: flavor id: cherry flavorType: Complex @@ -1128,4 +1143,3 @@ id: compressed-meat flavorType: Complex description: flavor-complex-compressed-meat - \ No newline at end of file diff --git a/Resources/Prototypes/Hydroponics/seeds.yml b/Resources/Prototypes/Hydroponics/seeds.yml index 7407a6b75fc..54c5c29d556 100644 --- a/Resources/Prototypes/Hydroponics/seeds.yml +++ b/Resources/Prototypes/Hydroponics/seeds.yml @@ -7,6 +7,8 @@ packetPrototype: WheatSeeds productPrototypes: - WheatBushel + mutationPrototypes: + - meatwheat lifespan: 25 maturation: 6 production: 3 @@ -24,6 +26,32 @@ Max: 20 PotencyDivisor: 20 +- type: seed + id: meatwheat + name: seeds-meatwheat-name + noun: seeds-noun-seeds + displayName: seeds-meatwheat-display-name + plantRsi: Objects/Specific/Hydroponics/meatwheat.rsi + packetPrototype: MeatwheatSeeds + productPrototypes: + - MeatwheatBushel + lifespan: 25 + maturation: 6 + production: 3 + yield: 3 + potency: 5 + idealLight: 8 + nutrientConsumption: 0.40 + chemicals: + Nutriment: + Min: 1 + Max: 20 + PotencyDivisor: 20 + UncookedAnimalProteins: + Min: 5 + Max: 20 + PotencyDivisor: 20 + - type: seed id: oat name: seeds-oat-name @@ -145,6 +173,8 @@ packetPrototype: LaughinPeaSeeds productPrototypes: - FoodLaughinPeaPod + mutationPrototypes: + - worldPea lifespan: 25 growthStages: 3 maturation: 7 @@ -258,6 +288,34 @@ packetPrototype: OrangeSeeds productPrototypes: - FoodOrange + mutationPrototypes: + - extradimensionalOrange + harvestRepeat: Repeat + lifespan: 55 + maturation: 6 + production: 6 + yield: 3 + potency: 10 + idealLight: 8 + chemicals: + Nutriment: + Min: 1 + Max: 5 + PotencyDivisor: 20 + Vitamin: + Min: 1 + Max: 4 + PotencyDivisor: 25 + +- type: seed + id: extradimensionalOrange + name: seeds-extradimensionalorange-name + noun: seeds-noun-seeds + displayName: seeds-extradimensionalorange-display-name + plantRsi: Objects/Specific/Hydroponics/extradimensional_orange.rsi + packetPrototype: ExtradimensionalOrangeSeeds + productPrototypes: + - FoodExtradimensionalOrange harvestRepeat: Repeat lifespan: 55 maturation: 6 @@ -266,6 +324,10 @@ potency: 10 idealLight: 8 chemicals: + Haloperidol: + Min: 1 + Max: 5 + PotencyDivisor: 20 Nutriment: Min: 1 Max: 5 @@ -719,7 +781,7 @@ DoctorsDelight: Min: 3 Max: 13 - PotencyDivisor: 10 + PotencyDivisor: 10 - type: seed id: corn @@ -1556,6 +1618,8 @@ packetPrototype: WatermelonSeeds productPrototypes: - FoodWatermelon + mutationPrototypes: + - holymelon lifespan: 55 maturation: 12 production: 3 @@ -1576,6 +1640,35 @@ Max: 5 PotencyDivisor: 20 +- type: seed + id: holymelon + name: seeds-holymelon-name + noun: seeds-noun-seeds + displayName: seeds-holymelon-display-name + plantRsi: Objects/Specific/Hydroponics/holymelon.rsi + packetPrototype: HolymelonSeeds + productPrototypes: + - FoodHolymelon + lifespan: 55 + maturation: 12 + production: 3 + yield: 1 + potency: 1 + idealLight: 8 + chemicals: + Nutriment: + Min: 1 + Max: 10 + PotencyDivisor: 10 + Holywater: + Min: 1 + Max: 10 + PotencyDivisor: 10 + Vitamin: + Min: 1 + Max: 5 + PotencyDivisor: 20 + - type: seed id: cocoa name: seeds-cocoa-name @@ -1690,6 +1783,39 @@ Max: 2 PotencyDivisor: 50 +- type: seed + id: worldPea + name: seeds-worldpea-name + noun: seeds-noun-seeds + displayName: seeds-worldpea-display-name + plantRsi: Objects/Specific/Hydroponics/world_pea.rsi + packetPrototype: PeaSeeds + productPrototypes: + - FoodWorldPeas + lifespan: 25 + growthStages: 3 + maturation: 20 + production: 6 + yield: 3 + potency: 25 + idealLight: 8 + harvestRepeat: Repeat + nutrientConsumption: 0.5 + waterConsumption: 0.5 + chemicals: + Happiness: + Min: 1 + Max: 3 + PotencyDivisor: 25 + Nutriment: + Min: 1 + Max: 3 + PotencyDivisor: 20 + Pax: + Min: 1 + Max: 2 + PotencyDivisor: 50 + - type: seed id: pumpkin name: seeds-pumpkin-name diff --git a/Resources/Prototypes/Recipes/Cooking/food_sequence_element.yml b/Resources/Prototypes/Recipes/Cooking/food_sequence_element.yml index d843e7b985b..43d6fe8852b 100644 --- a/Resources/Prototypes/Recipes/Cooking/food_sequence_element.yml +++ b/Resources/Prototypes/Recipes/Cooking/food_sequence_element.yml @@ -67,10 +67,10 @@ - Cooked - Meat -# Becon +# Bacon - type: foodSequenceElement - id: MeatBecon + id: MeatBacon sprites: - sprite: Objects/Consumable/Food/meat.rsi state: bacon-cooked @@ -276,7 +276,7 @@ tags: - Cooked - Meat - + # Snail meat - type: foodSequenceElement @@ -575,6 +575,28 @@ tags: - Fruit +# Extradimensional Orange + +- type: foodSequenceElement + id: ExtradimensionalOrange + name: food-sequence-content-orange + sprites: + - sprite: Objects/Specific/Hydroponics/extradimensional_orange.rsi + state: produce + scale: 0.5,0.5 + tags: + - Fruit + +- type: foodSequenceElement + id: ExtradimensionalOrangeBurger + name: food-sequence-burger-content-extradimensional-orange + sprites: + - sprite: Objects/Specific/Hydroponics/extradimensional_orange.rsi + state: produce + scale: 0.5,0.5 + tags: + - Fruit + # Potato - type: foodSequenceElement @@ -752,6 +774,38 @@ - Fruit - Slice +# Holymelon + +- type: foodSequenceElement + id: HolymelonSliceBurger + name: food-sequence-burger-content-holymelon + sprites: + - sprite: Objects/Specific/Hydroponics/holymelon.rsi + state: slice + tags: + - Fruit + - Slice + +- type: foodSequenceElement + id: HolymelonSlice + name: food-sequence-content-holymelon + sprites: + - sprite: Objects/Specific/Hydroponics/holymelon.rsi + state: slice + tags: + - Fruit + - Slice + +- type: foodSequenceElement + id: HolymelonSliceSkewer + name: food-sequence-content-holymelon + sprites: + - sprite: Objects/Consumable/Food/skewer.rsi + state: skewer-holymelon + tags: + - Fruit + - Slice + # Chili pepper - type: foodSequenceElement @@ -1056,6 +1110,26 @@ tags: - Vegetable +# World Pea + +- type: foodSequenceElement + id: WorldPea + name: food-sequence-content-world-pea + sprites: + - sprite: Objects/Specific/Hydroponics/world_pea.rsi + state: produce + tags: + - Vegetable + +- type: foodSequenceElement + id: WorldPeaBurger + name: food-sequence-burger-content-world-pea + sprites: + - sprite: Objects/Specific/Hydroponics/world_pea.rsi + state: produce + tags: + - Vegetable + # Cherry - type: foodSequenceElement diff --git a/Resources/Textures/Objects/Consumable/Food/skewer.rsi/meta.json b/Resources/Textures/Objects/Consumable/Food/skewer.rsi/meta.json index f99e5d77d45..d4e98e98bd8 100644 --- a/Resources/Textures/Objects/Consumable/Food/skewer.rsi/meta.json +++ b/Resources/Textures/Objects/Consumable/Food/skewer.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation and modified by Swept at https://github.com/tgstation/tgstation/commit/40d75cc340c63582fb66ce15bf75a36115f6bdaa", + "copyright": "Taken from tgstation and modified by Swept at https://github.com/tgstation/tgstation/commit/40d75cc340c63582fb66ce15bf75a36115f6bdaa, skewer-holymelon edited from skewer-watermelon by slarticodefast", "size": { "x": 32, "y": 32 @@ -45,6 +45,9 @@ }, { "name": "skewer-watermelon" + }, + { + "name": "skewer-holymelon" } ] } diff --git a/Resources/Textures/Objects/Consumable/Food/skewer.rsi/skewer-holymelon.png b/Resources/Textures/Objects/Consumable/Food/skewer.rsi/skewer-holymelon.png new file mode 100644 index 0000000000000000000000000000000000000000..8bc88a45b8c5d071f1b9621b954106bbf232acec GIT binary patch literal 356 zcmV-q0h|7bP)dTGMq2S!R)}>H6*%81p~3gg%38$tH#ihYvFt zek0E_EaYecS+3FZkb&XY5{8%m$ut29m?+Z@0W1Gd!xSRHqs!g@|GV4%|If?t|2P-J z{}((A|Ic$VkR1*rhX5$S!N5i;_?)6BXlIAel1vN?{Gr9zgkR(* zM6w(J%Ze7v5I!s#$N}UgLdF{<@(iF*0AnZsr2|q!fvgGyRw2P^LU6qR1IG?CFn%W9 zT(TShtBR2TxMqY_&kS<9rDRw0qhJ(_f)NH77#IM{4rkiNgXe1i0000o&h)SnWY5V~v z&t>dn%_ei_Xxt@tJ3Almy`9_J1KO+YK+O)UE}+n*>0HNt%|6+VB18avVmCr;k!WB| zrfr?`W1Awh5Dh4#GU{04_RcyA-YKw<=R~IY?zsg_AMd;KsZSx6AUA<0QC20yQo}jP zIg0O3$GOQ!E+VynMup|T=(l2)AT6$zO`;UI3GyDVnz0dJb_F3NO*i4iHIU|bIkI^v zpv*aPFR+ld__IJpAQ(QEi^LP7z|(V?zO|29SiLSbBkA}IVQ`>a{mZM7;B>k7K#C{t zp5zph#=Y~}0;Kg`qFi1j0k@|pI!pG+#~4X+@yY@=7l*!%Sf2Zr2PkeHf$koHZa+67 zui+U4ikP1USi8Fs{}*LOjVD2@GWq=YCFmoW`A2Kx-)eF=#ICe?xWcP@VELf~yuU?l qef_{;w-Qz?ZmqThZ3q5)2R;C31+uwlT=#JR0000&S}AGN*l8j71F^PI zw$Z{gMume2iZ*v1D$e@7nVZbAx$MpES?<8@&U`cTy>H%ovq05GWMJYc5~i@<5!3l? z&w_DmAHNK4)h5>++_PZa83cBPdTUPHX-g!IFtHlzspP9;BE8=38}tna1+y^%C9{#H zy1s}cJP5D|g3AlZJD29(imY9Ag=BMO$8KkKraw*t)h~y-2m%B<1>{JKOJgQQ_b>4C zV}w)tr2t{#zc5g{+BcX0-I%NWajJ z&`w#%3LB;CU3A7Z(e>}#TfiGYKH*QY4v_;~56H+Sskhu*~uZ6uN;A*nbdAwfx$!!4T;SJ!G z_|cI^gylzl178` z6a=E#9z;sJoD#hMz!jpqNJZN3?@;nnMr7Zb zmHyx!yDuMJ@(f#$ou?cG;SG5C3V1HJfd7XDu>j*fS1+BjZ~^Jf{6U>rHj&od;)mhR z(gobUf`lHR3=dzF&ok5m=@X~>)`00)nSSX42*%To+Da8b`YrI(ZrdyOEmeTko{(f= z?zAhYXc=CA!feu3?}Ge!zPoU5yY#QQan-9Bs2HdiD8Rr!@xk_9%r|<600000NkvXX Hu0mjfP;y$7 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Hydroponics/extradimensional_orange.rsi/meta.json b/Resources/Textures/Objects/Specific/Hydroponics/extradimensional_orange.rsi/meta.json new file mode 100644 index 00000000000..c2fd092c025 --- /dev/null +++ b/Resources/Textures/Objects/Specific/Hydroponics/extradimensional_orange.rsi/meta.json @@ -0,0 +1,68 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from https://github.com/vgstation-coders/vgstation13/commit/1dbcf389b0ec6b2c51b002df5fef8dd1519f8068 and https://github.com/tgstation/tgstation/commit/ead6d8d59753ef033efdfad17f337df268038ff3 and modified by slarticodefast", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "dead" + }, + { + "name": "harvest" + }, + { + "name": "produce", + "delays": [ + [ + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08 + ] + ] + }, + { + "name": "seed" + }, + { + "name": "stage-1" + }, + { + "name": "stage-2" + }, + { + "name": "stage-3" + }, + { + "name": "stage-4" + }, + { + "name": "stage-5" + }, + { + "name": "stage-6" + } + ] +} diff --git a/Resources/Textures/Objects/Specific/Hydroponics/extradimensional_orange.rsi/produce.png b/Resources/Textures/Objects/Specific/Hydroponics/extradimensional_orange.rsi/produce.png new file mode 100644 index 0000000000000000000000000000000000000000..be5b16262e5110216a09e87f7b76916ece884818 GIT binary patch literal 24211 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Hydroponics/extradimensional_orange.rsi/stage-1.png b/Resources/Textures/Objects/Specific/Hydroponics/extradimensional_orange.rsi/stage-1.png new file mode 100644 index 0000000000000000000000000000000000000000..484b4726603eed07836c35f7227ed5cd68617c93 GIT binary patch literal 169 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJ0#6smkOI9o7TJ!d#5x${A}G47N@ANTl%1U lYH!bl>ZW3%p28+5U9$J2baY;m*udXZKjymz# z6PI*Oe9I8M2{q=9p>ad>CLUfv0dQ&tPgvqG(P-n-NF{9sIXi5 npnPg?+kp&@o;C(fMFs{FYt484ZWlFyzF_cl^>bP0l+XkK9;H{` literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Hydroponics/extradimensional_orange.rsi/stage-4.png b/Resources/Textures/Objects/Specific/Hydroponics/extradimensional_orange.rsi/stage-4.png new file mode 100644 index 0000000000000000000000000000000000000000..31054ca2c5ce29cacccc61534279da36f89f79f8 GIT binary patch literal 359 zcmV-t0hs=YP)* z&6~gX{mt$oiock^zb9~5Q|9BL;?vCJy_!a7Z2ZJ%q>>T9;kdq3WSC>Wq&3_UlQHpP zT678#%;YM>=?XdnO15ofD4#(0O2i_V{L!Z*oMi(k?~YSIB77{rXSDrpis+Gsgvsd& zKmfwsQ8|B(z{E7{kuDp8)kCPep}Zf&+cY5Qg6iHhxrspyChE#y=pIVv#bIf|aHcY%FYTEG!IIMQr@2B$gIpBLq7u8*Q`_ z6$EXRD+J>{*(`S?A=x{Fh1@`HXJ>cjoqcC^BW3bm7#KWL?N86r4$#@$*pq}#ckRjA z1$Aoxx%IfMCkYUQp#1u`BAU?wU0brYf&JD!J_+>sY$~iO0HE|P6^#Qre&09NoB2vr zDjX=V7XNR~cWdocy1kdmo2mt4k=Nd=1bE4S!;&jSw4<};l>mXm4F!Oa#PW$mLcxf% z^CV%XBrw$(u64C*3F;?$km|KICj|`f;+-`0WfRi4l$*A}Kl3&T{G8qj>uGVdW{m5& zFU;Ep#12C)Buu!uPdO4%MnD=5>gfYYfxrs$+Ou>NN{b)T@sMdskCJ%z0H-=MrJxr8 z1q=Zkfo@7uz4iyUo?X6i8lg9S@6ovxZjW1Ibha+xlP^>AI1s%Mw00000NkvXXu0mjfBZlsE literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Hydroponics/extradimensional_orange.rsi/stage-6.png b/Resources/Textures/Objects/Specific/Hydroponics/extradimensional_orange.rsi/stage-6.png new file mode 100644 index 0000000000000000000000000000000000000000..96853e9790360317b587e6cb3bfd275d17d08c75 GIT binary patch literal 625 zcmV-%0*?KOP)uk`)0mxzVFSN)niNrj=!*+Ei{k0-EhnQ2jf}4 z;dTgBSqKM50{eN{4r{0HTi&?f_4&uJF8^Ytd|V$Y`lCjFsz0;#AxM1eiGv^Pn32!U z^wyJul!*7f?SCpI0MOOx-c13>PI(?c21Hta%ofiVwS^KBQ2?oZd$ZMjCm}G+U%xvz zL~ot-YT2N*srk^?RFOP?xb0QVDfb#sz{msM?z#e0O+*2aT0db1*zJpEvnO3@p0VN5 zBL_!ztkQ_pQ*O|lRDedpV|MATLI}SD`^r*0x{G0T0unKW68pg&=ZhhpcBk+F2q3?J&z)9OZLUN> z-UEpW&80wSR2oM|T|j-Sd#C80Z((V7ridSe=Q^qts1>Lc7(s!5ege`M_{G(!00000 LNkvXXu0mjf06ZYa literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Hydroponics/holymelon.rsi/dead.png b/Resources/Textures/Objects/Specific/Hydroponics/holymelon.rsi/dead.png new file mode 100644 index 0000000000000000000000000000000000000000..a3896d57c122b38ca7f2104763ae3e971726c959 GIT binary patch literal 317 zcmV-D0mA-?P)q$1K4;5kLVd}ygXV+qbhb zvtRT)TSmYL7y%<-1dKorfz5WABZX1Z)l;oGAL(kb>RyZDtm|BJoAkKJgcq(C@0UYg z)6Ch!V^f^%cgGRDpDY$eF$|%DP*>wOje93Yv*-|)d2EiR^x*|7znmjI-v(1D3zxS= zfJPEuyi=4odGLXq!_4MWxm8Gf8V*=H6k{T~Ci!iH(9d-U6z95U4@xJt`A*Vn)A}c5 zB45b}pD$yC2MYXQKXi2xK#|A~rB*DukRSs>)fX$V+9flLfDteP|3u&kq4H?TP^e6y P00000NkvXXu0mjf+8Ttw literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Hydroponics/holymelon.rsi/harvest.png b/Resources/Textures/Objects/Specific/Hydroponics/holymelon.rsi/harvest.png new file mode 100644 index 0000000000000000000000000000000000000000..1a2a7d37478ed70411c96a7ec13c09eae8fd3998 GIT binary patch literal 440 zcmV;p0Z0CcP)1t;B`qePCep#U5PtwGlbuZb0VFOY?EDDAk8mep)qGO`+o2DUC!`4k7MHGsO(yR7N7-a0a}0-aEO5R$c^P$70Zer z0z>s2w?}ULSoe&qwMs-*d>=9$X!SQ4`NRKfnb;o+^4iLcZ>{^(sI7K8li%L>%eF2^ zmlGItM0Tyd8~2)?AYnU{j+=NL<5>bmt z?AuljGu{l_$|1*9*y#YkYxn@y@D{4$pI4s2)QvfZ#ry|Ls`B?*vOiz{r@-DOJQSsA i_I1l5*U-?=0Qd#^m#q?n0Ye4=0000bc|Wz%z_!`l=9lA95!(b&<^(MzAz86ZM{6}S>{8kw3wsh|NM z0DytODwP$2?N{?Sjm%ec{&GRwM#xrez-2$w@h`;@+ezUW}Yv~+dr+}Nl4n9i;+|SNZH}L^yyFN#G zfmXFV{_%g)QX@G36)?+h$^e7dJ2(PaVFwU)7&(Xhl)(M2HAb|8zbOOmXJ;t@xQP$m zo+xC6pj6NxD+IDa(BWl!fFa1+6NQc>pLbIuTFKwg0Pgx3afcVsidDeZg%YX&fM6g1 z^*}{vI0Vp106<20jZ#5_o@PR<$6|BR|j}Q#VML8+s}M zJ(YmEsWL(I7?6HKF8dn6&?NM95h+QGeI8oA~^I3RP~4n0uT&Mf`mNy{ml>8 zeRpB}m-c|aJHD1&i8%F#`;b}NfIr*^Z%-5eAS(nUsCTfC!wd=|GZ&# z6jZmq2XMY}jd0uiS8jsFY0n?-gEBaRN@*YW9)#H~Mq(6ckAA{i4U2z4IZNrk0}18j>1L&L&&4CmjHmGx{I#R6aLzOaqzI~>9CdjrXGfj zfPemY{uq4KDXUeF#jW6%oYGjE!!ba#0MT#^5G_D7+TMUWSsk_$mVOquvpii35es1Y z60o~GZ3T9g=S^pT-Q{Vsu)92OIs@!3Pn(6^<@q~T9k#nXf9I;h!utaNvDIPW{Q(!n z++_Yud4=@{{8u2pKi~>D{Q*vYfYToU!08Wg`U9N)0H;5|=?`%F1DyTsQA5h%=FPvKF7O1P6L!?3^CA3o) zLu@eRb%;+CZM{e(9o{Vu?k@NJ+`Y#U#yLlxc9N^Q1dsp{;6DJIQIZ&A=vfB8saD|l z0e(9Hp#C^u06JORl3# zAr;&$delcqEk1pFC)XtHf%eE_jvtW4r;9JNN8WK(F{P*wC)Jj}C)F*Js(1+;aGdLDXH!Bo$DQe9~9O)q_KJ z-KuCYlLJSOk6+LfoxoldCdZk`WU8-P)r?7cY;BtGDe&h-0SVqlAW@~rz_56dl%zXv{vV(l O7(8A5T-G@yGywqa(mK)r literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Hydroponics/holymelon.rsi/stage-3.png b/Resources/Textures/Objects/Specific/Hydroponics/holymelon.rsi/stage-3.png new file mode 100644 index 0000000000000000000000000000000000000000..69b583f4e413fb00c6df44ce360107a31cbe280f GIT binary patch literal 291 zcmV+;0o?wHP)z0 zCf9NX1{_g<4A3n>4hfj}mopCkoh%_@r+$;>AiRk%`?$mZpKnmb7Q`N4FUuKJLi9Y}I>qEa5OZR1j&Zw>&XcH(f_$e3nvW02%rXR%=Ic&<6%7=f*}iQS2P zezxU0cz86M)B^LL4==EjmoP23-Yk!ESuEIX*u*5~dbZ^{n2rIpFwY;94?t%Gw)UfV ze&zc8#dM*R0HWqy)c{siXRoROTn__yjbO6`ZthLXZG~&D??yl{9UpSvs|uM8Yp&H-)yWTi8}R4=i9{m(w|)Uja*eR_cr@Ao0000@v~6M7CoI0U^3B{!g&j@APhV=PP-3uOh?EFojD z3_Hs1&c=pjzGO0)d71hDdGBr3lTva_PL8VX3^)VMfHU9>I0Hot^k+hub6PAbUIZ`g zcif)|HR?z&Yn^5yD{dn*1HEzbqWSdq+7zBo|1S=3`gddh+D4*7?Tc$vjM!uJo1oYoWT)sMze8ZTeJb+mgo z802%YmVy5GGVOr2Z)R#TIy>(m3@@a{&sVy1fIFBcq1_V)Zua#70362w0JyGuC1C$R zM7?^m>J0Q3P`NWKeO{_X+j1L3K&|!}0MO}#0Dx-slaT1n$w~Yj!|+040H{;h00000NkvXXu0mjf&TtA; literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Hydroponics/meatwheat.rsi/harvest.png b/Resources/Textures/Objects/Specific/Hydroponics/meatwheat.rsi/harvest.png new file mode 100644 index 0000000000000000000000000000000000000000..b0417c69c0ecee1f04cc91c01228db449c9be68c GIT binary patch literal 1208 zcmV;p1V{UcP){Qz(FY=XseHc{;8yew0DWDZ%nY9rdVYtlP&>E7D-0AHs5v*oQ2>s2ha>?j z-rwC>k$?5L8|sib z*4k1V9~}{DjhW$7W%u#>4=}ejIqEaY>c|N!M^+F*&=+dwdLm8ceu`a66PS7L9iiv4 zxpZXTn# zmF9p4-RGeOjjLx*i!Pr|&{dD&_wen~3a^AZF#H~7=jP>v`noy^_?noVo9BtE37f~u z?2Sd58|H! zmP~SJW1V!;%fQ&A_Vm(c!ti_e;pzgJL=#Wl9)b-H7VbvraoFjAZ2^NEg_kI1nuH%F7@C;Y2F4~ew9;E?vlh9WAZD6G5+*Uz z1W`!3_b^c?s0TRgv~wr3F4vZQ%>f@v;S~-$?X(39n(Yo&6DGB`8UO~zr?kx0rfe$m z`APzTMkj;gQ`+5Biox+I&2YN`IO+??f&fRoI;#njYw1lnf#szLk?b}As|l0uZrx;P zVp`i3@-u>}T7@KVpt$tb*A?=MXJg6I_yAu0;wx=vVp{VYszDkRnv#?~0{0WdT^rQLbBQLLh%TevFY zlZxEc6$KidWu&c`br0pL-)`|~~rd6ulOOa)tO1j#;1!vuXN&+>uLKBzW zUUA@giY)sq(pF3rp{o9Cd#92>c4xP&>5tcMR1(=kk!9aMK~=3n68QPXA^k!4?IJyj92psKEF!M3gXd%71+x=I8s`zTsvHOMOuYA#=zUR4X~iU~L4F#y&d zmA+h-BGs1l$ECPs-|z9YvIal>`iIP^RRp#wLTo&P-XkqQxdlg>JOI3Q@+G|-DQZ~P6j WxVZgL}{a zcmMai$9+mf*vYVVRQ>+|fQUSFcnS0MRZkPE*8eX6T!SlB8(m$R{gS`S!8a^j~uPF_mlUiD;);TMsFjv16xiyJ8`kY(n)+B3l<3tX4o@YaM!kMR3+96dH7n->PjG(+xo90WoqPm%vN z4jr9jFAh>Zu$Lz;CzT!>5p(kdKml8MTMndqVls0_5$hDPS%^kqK5NktHLR>aunC+9lq=BnO|q)swj9XJ z!~Qm5Y0-5+1jGm;P!vVjf%LM1ir0#6*j^_Zf#N1uHl#Ov6tp2*u<&b5bI1j0b%d@P z)p!4I;n@LWV0P7}qCuk&f!LFpRLRB|7tqwBTrWUNGjxP1qzVD{wN%Iy{bUxw;3FJ? zyGshAA0a@Y1X|!1Ld@m-bnn^ZZl#HR;Syq?%@GcKSD*cL0ptsCuLwS+aI6Xoi}0%i zaUw9a5WqCze?0(!0Hl?}yx0_VfEjT(qSg_C{mq*kOw_-7&j3F>6O)w!q{PqD)doB|UP_DkZxB=q9&q`+>&)3r1rv)_nzU=u-NqW5@pucO2kP`LAALHbPz% P00000NkvXXu0mjfG4REd literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Hydroponics/meatwheat.rsi/seed.png b/Resources/Textures/Objects/Specific/Hydroponics/meatwheat.rsi/seed.png new file mode 100644 index 0000000000000000000000000000000000000000..de775fe7ac9e55debb33d73fa01a9f019ea844bc GIT binary patch literal 406 zcmV;H0crk;P)#$bv;p|Si7{t3w(y3G`3Vo6OC>{7u5g!;}5 zR#+L=jinQP%_Z&S-lun8uT@!=QKc>_b*}+xfEwUG09;Cvlv0ef&bp4nEJ^q-0z8DF z0+1}ZQXR03q3bx@4u^%&HU@ye^Tg{_Nhp<40F1THbhCLhuj9G^tfL43F9_7B+M*F0 zs%=??*PrKeI23Nfv z@pLLS{4qdYdGp^&^cKvLgf5?5xX;b}P-WUL1}Iy6k*4CBq7h8uSV>RyB29@m8zyml zatlI<4tx|8?Rcp<2)_k?smlKcYJeJ`2B;k19fNOop)w!wjQ{`u07*qoM6N<$g00TA A?EnA( literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Hydroponics/meatwheat.rsi/stage-1.png b/Resources/Textures/Objects/Specific/Hydroponics/meatwheat.rsi/stage-1.png new file mode 100644 index 0000000000000000000000000000000000000000..efdf35bb125abfdc8bb6dbfbb91d9c1f54ed2509 GIT binary patch literal 391 zcmV;20eJq2P)S5XXNt)|e(J)LwjpzJT|>gd%v5f)xb|^-{1s`GF@39{U77N6y|0BH~H3)>KfV z)qW5Un~e#nXimB8z%tD4{AYeMo3U-1G;Jo;?g~HwC;$bZ02F`%2m`blJ6@^)%lW0L z3Dxr2zrjwbn~8@A0AAepsR@Rb1>n57`)Bb&As>m`NBa@Yacw(RBLG;mOaSUz8&ey3 z{%z}E&jV;w)?;~n=Q$EPPtiDM%*E=)HlXVw>9kfB4Km{0(B}d87z_chOd}}LJ`|Hq zG?7!Uh#}-gWG$(^IBN#*u?_rgLSveGmw zcLFdPCQ`!KsCLckbUk!UlZ$YGNF)fr`tup-_xp&aG9o%2;Ap>$skn(oFYA?xj-0s4 zznXm_J#HuS*$oRu^#6z~+ENw8>*Da}ghx}8RI4@4hg_&$7saxU(*cUlPc-1WcG`{f zQ>i*#me)QPOg#u(cI^8B(&eV#*?{U{ZZ#)hUx@!SA z9D+`(#o}f`c-&6nsf^e=EE0dQES7TH;;h#rxw0-op>aUay>L*gof1zi3jm|pBDt0q zoo0*ag^VawYRtXK3$Lp7n@z9xi}~!j5Dsw@U~V-hO1g2|oZQe-?!7o|H<0qm(^Tcw zto##N+$@OGb_0OpihdISKnzs@Xt(zOXms}hNGD?Q<-43nCt`AXAtTa>n9OeNh<+X5 z%ic!-%Jr`RIERk`_*VR6-6OlTBhrbO?7x2)7{Y!iY`k6o#McxCFz%VB!Raz$(9mKhXSyN)>Wq{MCiiMGZ&^UAT!qVymK}>LxpjKah>3 zDC%4Ms^;grI^bM zjd1~73+m|p30mecI}c9-*A^G#Mkquvmys!52Vf_ck=-YcW&I4yd3QS&qg1Vvo1KwZ zG{TgwQ>q%n@-u$^p=Ftf2;rd4R4_;}mz8$cLIB&c=yZDkRH_E1-y$BJ9>i9v222a_ z=rl+6-;^r`a#M&$BSQgP4rKEMRc_-OX~bhdE{)0Vq`r zKHLPG)*_a zo%<{5`ODv!+uT-@T7cBXma5bnq&Bt`z{J(70BD-V{OTiRzkNf<@Bbu!K=YBw7gVp` z2Vna86aaIpkJRr6`(%ImSt$iQ+jav0ydN(EaNK(ZKD`M>10Cge7mC3 z$%JU$#$f-v_FBIJpvDdWcvX5a_{ZumPgOdZkkrPOa=rsl&b2(9Ovv>BG&}HL>qYw9 nSZ7WD_-yF$9BHJH{y+K$BxGzl6@JV700000NkvXXu0mjfba;cz literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Hydroponics/meatwheat.rsi/stage-4.png b/Resources/Textures/Objects/Specific/Hydroponics/meatwheat.rsi/stage-4.png new file mode 100644 index 0000000000000000000000000000000000000000..8d471502ab5c6d2f157b518fc649841239a15027 GIT binary patch literal 835 zcmV-J1HAl+P)efkn@Hy(ErEXz`rdeaUY4_?Jy`3dUmt4e-? zs*03VnxyeCLrO5rfDMi<`F1f348@TX$&wf4+aS)l=iKjn=VJzOaB#p)B6g#<&k4*4 z%n5udfxV4&xo?{CMhN^`Gv$}13bxz4&ih%6e);jcZ)Gx(AQ?|!)M_G(|Ga9*6fszq zRLaEDv2E!p=-~WoNlBRRq=V-K!yq;m< z?3{XaO^WyL$J2(e8!mFWK&4!yI~Z{2xb!szqi%`qYE>3;IbJyq`=%-Vo`-)toG2hf z;E`N>iQ)Mfw%eq0+{bpCZ0_uePS3|MO`)cjKtTI+!1GtH$MORhbxSn=Y4OL)m%QtG z7j)Y4qDo0+I zyq+PON?p3s%_lpe<#hm1(@6l@UKjuPgq)_2SM$bpCj_GV3z1cnndVXk295qoE<-A@ z6jlJi`ZOiQk?(Qn1jF7dM-*r{P2Rk9FzS{_#N#s!lcSgraO8U^;|rz{P8?MXf|^#R z%jV9m_^&x*04vs(cs+9XRoL9w6)msB$2^ZOE`n1(Mb=`wlVQgM0KO>XN9=>5;^&`@ z8-=QbljT)?Djz~gr2)vQ>P+sAmH~oc{m`6I0x<%oE-VD0+qWhU$uM?nF+3xt@*yVq z*&eaT@vJs6un7MZKmPu~wZ7%9!s92uO|JmpPWsb6ud8;BIp+9(<6p%?L$Qczs5Jlp N002ovPDHLkV1kl7l*Rx6 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Hydroponics/meatwheat.rsi/stage-5.png b/Resources/Textures/Objects/Specific/Hydroponics/meatwheat.rsi/stage-5.png new file mode 100644 index 0000000000000000000000000000000000000000..bee9bd6b93d4069f9ee6d2913f41de08b30b6446 GIT binary patch literal 994 zcmV<810DQ{P)rM@sp2bqF+IcD@^CV6u!SOGb@t-QZiwV zc1`vymy?E(VRG)i_-1BSYHEUX+Ti{9Inga9!a!CtxScVmI`zQ!bbdh&8)?Q(lXrBD z9jo%UiF}53_V)o88#Vbij71ozI&~xlgPIZXwa9Q*KgCH6FunXZsHVN*{fgx>G&Tl6 z@cjnHIsjz#3|b=2F9#LY@=H<(!JuZKt8q$Bjq1@^N5#)y{KO=1$27^NQfzE)Quu5} zzBe{THl^|X=8HE1h_qn(;iC9)XPe=80)Vn*f$)|H!H}v3YkLGpq6b3YlB2{Gwrh31 z+t}dVa-nPgBMkU-CKZKo(_}D}LI}b0?JdsF6XaHk;@i)^kPwQpIWiidyfI+YR8-Q5 zeoC(n7)d6AjS4ffG7(SkQGPK3DArDA*|HEqP_`_pjzih9$gLE`;b{$UEB<;u7l?9L z*Ikx?sX{@Nj*h80HSFKd$m$td-X>4y7o;ohT2QP%PkMdyu3$`#x3?k;01PM!09rE1 z&(&jOAWAzz@sO%=(XXH<`Y9d0;{%8kjRt#O zb)iWH^$ck>&f)nPrK97Ho}M^0j!tcID@EZ;B&%o8RfQ9$&Tgf`ueQyEX@&rHEsG=D zVcaxP`{GP37sL-QUoz!Y=SxjX>73Xh#qFZ>t-WQbr2D_>#SCgj+dQ$N47B$XU?`dF zNG`!UmP%w;T{gdEKJ<15%3iS%2KFl!C2Nm+%LNhdk9(ov5mWnIp8!srdPwml^DAy= zjP{t~6LDF*F>nw2#_6kyXRHK-q?-Z*#F!90zKEX6y-QJ QmH+?%07*qoM6N<$f-W4~*#H0l literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Hydroponics/meatwheat.rsi/stage-6.png b/Resources/Textures/Objects/Specific/Hydroponics/meatwheat.rsi/stage-6.png new file mode 100644 index 0000000000000000000000000000000000000000..502f27714c1e1b7dd7acfc8770bcf75e77d71057 GIT binary patch literal 1003 zcmV6ZO{%n#*sMJS@+(+obRU(&e-N4qY8f;a5fw-^WZme#) zYAjW4gRxcaq&S9Q7*ZLds#3UJ%-rE#7^o|?%A!6Sxc8iU?)kp&oD1ae@DQTyZC03) zO5>B-mqgtErcz<=t`-rC5!~O{kbH~mpju;jRmFqP7RSfL#r{^66-^Ue*O?0}TNVnc zieqYDH2ojYjR%j0i~i>~W{F&%}xAqDMy{sqerhRG_!npIqw?4Vj>x~Ag( z#s)ck>0i7o9++XEkT;;Fk`e>^TUEBI>nK|m-cePwD2+_S5jWeu|8DVWj72hFYP!6q z85p^J470yuyyl0G!wqj4fwuAp_^GgXd2h3;+yGhnh;DGajRPb{2_N zM%>2UW`+G7W04H>Tn87I34HXy`_QvF95ouOH*i2;ppZ9k>yI%+wD(F@c$OnBTNZkw zFcIh@?d+x}GO9@X|(;QcU7$Xz3Js{VocM68iTxD{OzO z#v%&{XO>bBLeLTzc)Ytq&b&SVfB|^6RgKhleS4cUJ00`}4!qGN3V8#Qz{lU0bGH|Q zT4?Ogq?T;FQ{MUJr3PJHw2@)O2YgW=)igF`schUA;jcC)CEd z=b>CGP9-?8eNES_5|Z%*9@e+X_dorNhxKj3sRw{uHiPcKK_PFzOs69Y5G7NURLFog zx`e6eVFS0?_Ot-r!N;^M(K%}j1g2(0{#J;Ea>)V$BnEf`uLTY4GZ1v}dc97P@r0BN z01|OOApwIk=p&s>MHZkbY3Xb(n*kupGTXp0An4!)n$8-hcy6BHGbGw12zn&Q(z2&u z!vX-zX)0cjiYFysW+e_aq6c!BdD*ySZ~M&7f(;Ac7doB`01}q|Z~y@K^|#<X z#oQ&_PlEYvFL((Jq4=`p@ji*Wb!x2mpHepMCyYXRqzruI>MA Ze*s|I@@E1qo2>u<002ovPDHLkV1kLX)lmQd literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Hydroponics/watermelon.rsi/meta.json b/Resources/Textures/Objects/Specific/Hydroponics/watermelon.rsi/meta.json index 37bc00be888..16f3df4df6f 100644 --- a/Resources/Textures/Objects/Specific/Hydroponics/watermelon.rsi/meta.json +++ b/Resources/Textures/Objects/Specific/Hydroponics/watermelon.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from https://github.com/vgstation-coders/vgstation13/commit/b459ea3fdee965bdc3e93e7983ad7fa610d05c12", + "copyright": "Taken from https://github.com/vgstation-coders/vgstation13/commit/b459ea3fdee965bdc3e93e7983ad7fa610d05c12 and https://github.com/tgstation/tgstation/commit/ead6d8d59753ef033efdfad17f337df268038ff3", "size": { "x": 32, "y": 32 diff --git a/Resources/Textures/Objects/Specific/Hydroponics/watermelon.rsi/produce.png b/Resources/Textures/Objects/Specific/Hydroponics/watermelon.rsi/produce.png index 61e3fb4eaf83cd02127d145ed9ee47d1e2ac6869..655628bc8819a23c9c44919eca3c1d78744ccfe6 100644 GIT binary patch delta 694 zcmV;n0!jV11I-1HBYy&vNkl zNQ2@cLKX)nkX=x~E3l&;v5yDXn8G3}C9a7RBcCkl5at_z~ zOwyzYtx|`)<+%I4@BY8{-v1uwSy@@(Ji~jg>Ro^?Ko{VD0Drh}nnUB0W41S7HC?Ng zWnMm=_xuw8S2%tzB%YOa>-Q+vVPa;~?i9q+$tWJ59J2wu0gIt<2qowUD?w-7ulBNM z9Ml16dXZ{b1~?IexpU);XtN@Pb)WI0*OE~}m(g*`^|K<|_bR!EmUg)R- zjS#V6g-S(cK(&PPUDvCFF^q3H0adBUNRm}|E$rlRE1F5q9Rp}N2{Y+Ak7;_)^dg0w zJllqh5`TnkLniaqslfVD4!_#V=WIcobF1Q>i}Xju=h!UT4kFhBl4J=pMf#&GuI7&f z9W&;>l*F0n)sXOnrspxu=GnIe$fV~y$yCDjA)`?g26Qv44c8}5IHs)~My;ZwNtjF} zYyh9n#v8EOz7(9#b+6DP5;+q2YgholS8 c1?U3&25>YycMB_d+5i9m07*qoM6N<$f+d+jv;Y7A delta 414 zcmV;P0b%~l1-Ao`BYy#YNkl|Sm<0f0M|%FdE%J1o??x^_Ah>a$88|5#irHa10Lagly_!8vilkEj(RzNB`(jg~bzP+c%;j6KVa9+lFkVUfl{L_#2fjj68j1%!pXz@@m#Z4MMfBwS%*h=o|D zG?0L$5nF{=7=%d?c3DsFyj6)Qoa(sUyZL7Rnb{?X2#2(jgL*##{09J^+hVud_4JdP zRl&Q=J+Z$}CX*Y#-8uuNK~Z+j7(>RGa!YLu5C{aps_G*0(0mM+Z_n^#JSahI4KSTf zAd@eNv_}Sg7)Ile)ygYU>=mG9RYZiXPE$N5^ahCx`l`QE1K@gd{TJiUrS*i~P>Nm& zpw(##y$c#8;ft86uk8U^ohGJJIpyf~29QqWh^#la>2$KPciq070T^TW{qYWRpYx1Z zRb9-3npHt3SSNFxgxo^&F+>J^$m;7`%xMyOF;5xDYGpEv#^JSevlLlDqXYmzcCK14 zp1UA2=&!VyJQKLtrP^e~?MCEu7}cx_E=D5&_#Mf!Q@_XpV+=#{F#rHOHeNPn!gB_A zk(ma?#b^Wtjgmkh2$_6|_`hbN`isRP0RYb<*|i9{o~A*O>)mVD@#^|kypz{VgJSq1 zrgR=`lwh56JD~kLtEyurUm|AvEQKunI(uOP_RzNws8i_~OjX?PScw za`<0yV@GJ?=5`u0|3){}(GtKtTd2i){V_z&TiS6u#iSGix+_s(4!q!1GMUCQ~FN9xASX z0nd8cmZcD2rI1%4w!i&Axl|DvD}A7T)c_El2UYSfG2vUp@M^SeZx8}Jxv{`j3VBov z_falYz-N-eIQnxo5+&l+nLD_8H;PM_FQQugg9|sGxAG4rx)F6cjQlwpnV0oy6|9{f zYS;zo%@my+JC422ub{I$!cxSAU)vGkBD!uwN|Gf)PCA<$g~JzThI6MN1=Gy1(4TdMkR0P4gr2LqwfJ zkO(=+;fph%cKRua2Q=1vz0}(%((`@5;fpgqH%Y)j)+;a~=K%0==%?BrI!Q->=2a^q z1=A{6vwloUvF06UCBhK=OX>TibO0~_7y$eQE?{W0fxxXE00000NkvXXu0mjfYW7E4 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Hydroponics/world_pea.rsi/meta.json b/Resources/Textures/Objects/Specific/Hydroponics/world_pea.rsi/meta.json new file mode 100644 index 00000000000..01be1e7dc4c --- /dev/null +++ b/Resources/Textures/Objects/Specific/Hydroponics/world_pea.rsi/meta.json @@ -0,0 +1,32 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/ead6d8d59753ef033efdfad17f337df268038ff3 and modified by slarticodefast", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "dead" + }, + { + "name": "harvest" + }, + { + "name": "produce" + }, + { + "name": "seed" + }, + { + "name": "stage-1" + }, + { + "name": "stage-2" + }, + { + "name": "stage-3" + } + ] +} diff --git a/Resources/Textures/Objects/Specific/Hydroponics/world_pea.rsi/produce.png b/Resources/Textures/Objects/Specific/Hydroponics/world_pea.rsi/produce.png new file mode 100644 index 0000000000000000000000000000000000000000..aee68431aabbc177425dca6b42acd360d2987b0e GIT binary patch literal 512 zcmV+b0{{JqP)GR0J(_`;j0CR#DZNxbd>;rb!v4wggXG|EVI?Lj>Ljo zMVkQJUJ5sf2$S2eZFp8`01$}~wE#!!NyaiIZuieB4RRA3;z0nM5N%_CqxGcS zAIp^NM0~Y?k+~}XDWzWd`JNxymxRJ2c0Dw^&7aW*7i%f%=O;|(_F0|$h*HW3z-SLh zDRt}8f2X-qq3{S(haYHN`jJu^?Sp#(q?G!3Xb6CX`Byi3_2OFqo*oAoSjv-3j8pjZ z9sje|!zG}U62Iye(cwX6-b|BBjNb`yv6iCr^}zne#2i4HeDn`Or?wL0-|gA;wqYBh z6B(ZaN-0s8D~iB@in{v0000 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Hydroponics/world_pea.rsi/seed.png b/Resources/Textures/Objects/Specific/Hydroponics/world_pea.rsi/seed.png new file mode 100644 index 0000000000000000000000000000000000000000..fe7c87282098725c2ec838ea0e8d949d97063fb8 GIT binary patch literal 2832 zcmcImU5wOJ6z)P;{$wK>HY?GjlnCg0r?)@TX)6Q5%)*XwU|l9*jWOZQy|=T?&a|cN z?#!+x@{cCG7~{)E6BAy92T2Ssh(?W=7~w^OMjnkZK_VCuABZNbw=#l@RT#_wk4baf=B*76;V~NWWm>VFtnmB!&jj8kSz&Lw2#a2h zj@pA$KHW35tAwYkik3Vc%}9LoyZB7^)$ zafr{kKIOF(1QHB20^t3?$8jswrjo_$M%HKC#T<{EpZbd&>%= zVd$BnSg+SpbtUEc6;Uz_Lxi#@%YaFMVA2Uu131C@wuU?nuy1>z?K*s<5tZHXFe@-m zTOriEM6DCVFfqWy2J%EH1*4Fff&?dW-nd_F8Yft!Ra&D?7%*8Wk@ZI1&<#f2IaDW~ z?=rxkEfy0Sv-(o2B_@J!V1k7a12U_0P@43pI7|a~+{biag1NcA9Ze7p(>r)BU^^3U zZuZQaPf_UlCD*OCvpm#}mzSlK%x~IjJH)LAPes<^4K$BJniW{eRR9$r>m^Ay6_$0W zA4(>KEzzP&Y-_SpG!39sk_=PPO_=V7@*PpeH-bVmuQ0);<@zlB62B8?W_vc+a9`PsI-zp{IVy5Gcdn&Y4%Q6&T zQA~l3RT=0KAwYpDmUM#Bn$ZG}d9&NMSv8|-r`E_T!ZeoC5W+OkfS#rqhQF!+17ip@ zZ0Kc$SW;R;QOz`IXb#!|%kgAfg?s4!_^E31P3D;hM-`P7aKr{mgm~GW1&;+;j`!C` zDN}k6mb9z~t`*jiPq$SVcJs1OoYQ&NnV^1$`yTQUYh=_9vV!HiH9lbsAG$p9ysC{+ z6u3CykhobSsS@V26QGHEL!>E&2DNeq7-b0pHLbEtD>4L`vYde#qDt)6hPV@=c6G># zsTl3*_%9H}@Z(YBR46+J#QO-wfDn~6g#aR37BCFPw6dl#R}F|P*&>i+GWQDRu2O%% z!QgorFi+AWUL+)$8#F?FyMqIrJWE{Qn~eK^?9I!#g*B-b`m-_a0VPR{j_6jq5&zkV zTJQN5k~^a6Y@TA~Y&~b89Aw9u$vSS*ga1{xjP1Mk+jXP9(G0v}R%tJ>0VsM*CNK7q z%x=_SmFly}?9{2>&a$cQ+d_U@X=FLRH8ZpI%je3+UR-*@+;_R_WDo!R>W7aU32vVm zQ*ZBnqZ@T^djI3ae{L`jgC9RV!}YIv`?zuFbk6}pc=DA;Hg+4_mDOs%U0M{LxUpuB%yj~}@4D!I5uefo>n z-s}J1=I-&O{9irfv9HU0-8X-|#*vF?UDt{w(+2nQwc|^ky|nJ?xq};e_};_cEIw^= v=N{sJ@Tb>&bz$G>y*o}`KN$Oc_5%0L>l=@5SzB2d&8&riUHK2U?>qE2rw@{% literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Hydroponics/world_pea.rsi/stage-1.png b/Resources/Textures/Objects/Specific/Hydroponics/world_pea.rsi/stage-1.png new file mode 100644 index 0000000000000000000000000000000000000000..abdff1afc7ba31192be65e059714371267b2ae1a GIT binary patch literal 353 zcmV-n0iOPeP)b?aRoDDO>I_ncK{B+0XP5$-~a$zjZJE;tqJNf;xMg5-b#Lc zAkm-mJkJ`xNCjdQ{4k%YMF398d6qd~X@O07D|!FE{Y#2@706r3bs6#g<=Z?~!R%+% zWPrSt+&2!>O5EMvASoJgc>6@&%6SmX{OdRzubGJO^tfXp0ukYOzvZE?S!ZI1Xf(GO zV(d|>weGGN0I1C8q-eSW7ps7W4xouy8ZR5WW`*p;Nb{6uRdJlum+fAxjAe{)Q|CaR~Se0uJJs-ypbj3DV^rIQ18F4;0tX zz1Km`hBSFmU(gJG@KE&K-RIqR=MzK(U1HE_^q#;q5V%pjlu}l5;%64E3>1gYP18JU z+c*PB=#VOSRcMtUT25(Ypjbq+#=WdXzztFX0I+s9?Pb8vECK-7=DYG<2ek-ry}ABR zA0yrP^$4)oY%dm{50~j+Eic=A*DZl#sM`^Z39$0_=fNVHQQeMEPQt1v0;2$bPi@0Y9@S2^|{06~S8>#eQbdeqh^+#pC@QxIro=Uq8*KA`zWjlld(n zBD}tg2oV7hVg5X%V^`kCHi)S7%}b~brBX^rLWgWG768THkA(-o>i;i5wz8|eH{+7svr^aOqZOD5!i TJpOC?00000NkvXXu0mjfCP=vr literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Hydroponics/world_pea.rsi/stage-3.png b/Resources/Textures/Objects/Specific/Hydroponics/world_pea.rsi/stage-3.png new file mode 100644 index 0000000000000000000000000000000000000000..6ab196981f4da03918b99c98a77b98fb9ca54119 GIT binary patch literal 556 zcmV+{0@MA8P)I~a{dnLpx& z7JEiOx^vSswRbnpK)+SxEaYj}ssyr8X3q%7kv7Y5ZKHnPN`Pn%2>^UCpy|&`I9HS0 zB616GLyG|*n$6?quituHJa5ClKFwVUtqFDHo)M6$f9d`RFo4@%7X)17j$kaZOITUD;qyNLvHTw`(8p>?A;R~xRv4J|&NebAmSGPoWa^^zM}+;3I+_+~-w zNPFY8DzgA(GDTdecj@HQAw+XX#mCopD!!`#6{fV;wTJRj1KDquBg1yzQm u_kA%SU2CpFTY`UuoiC+(0eb;^0lxu%)$;}gGf(#b0000 Date: Fri, 13 Sep 2024 14:04:00 +0000 Subject: [PATCH 017/138] Automatic changelog update --- Resources/Changelog/Changelog.yml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index e1c92ca7bf3..532c8ed1c01 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: TheShuEd - changes: - - message: anomalies have the ability to gain invisibility behavior - type: Add - id: 6864 - time: '2024-07-03T15:14:39.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29120 - author: ArkiveDev changes: - message: Railings can now be constructed in all 4 orientations. @@ -3916,3 +3909,12 @@ id: 7363 time: '2024-09-13T14:01:26.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/31649 +- author: slarticodefast + changes: + - message: Extradimensional orange, holymelon, meatwheat and world peas plant mutations + have been added. Obtain them by mutating oranges, watermelons, wheat and laughin' + peas respectively. + type: Add + id: 7364 + time: '2024-09-13T14:02:54.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/27624 From 71d92c9f8a2c5c58bbc8611304b51741cafe6c75 Mon Sep 17 00:00:00 2001 From: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> Date: Fri, 13 Sep 2024 07:19:32 -0700 Subject: [PATCH 018/138] Set default PDA uplink and music visibility to false (#28373) * Set PDA uplink and music default visibility to false #27376 seems to be the PDA receiving state before first PDA UI open * Log error on PDA state received before first open * Fix logging * Fix error message --------- Co-authored-by: metalgearsloth --- Content.Client/PDA/PdaBoundUserInterface.cs | 12 ++++++++++-- Content.Client/PDA/PdaMenu.xaml | 3 +++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Content.Client/PDA/PdaBoundUserInterface.cs b/Content.Client/PDA/PdaBoundUserInterface.cs index 37ce9c4280f..2d4033390c3 100644 --- a/Content.Client/PDA/PdaBoundUserInterface.cs +++ b/Content.Client/PDA/PdaBoundUserInterface.cs @@ -4,18 +4,20 @@ using Content.Shared.PDA; using JetBrains.Annotations; using Robust.Client.UserInterface; -using Robust.Shared.Configuration; namespace Content.Client.PDA { [UsedImplicitly] public sealed class PdaBoundUserInterface : CartridgeLoaderBoundUserInterface { + private readonly PdaSystem _pdaSystem; + [ViewVariables] private PdaMenu? _menu; public PdaBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { + _pdaSystem = EntMan.System(); } protected override void Open() @@ -92,7 +94,13 @@ protected override void UpdateState(BoundUserInterfaceState state) if (state is not PdaUpdateState updateState) return; - _menu?.UpdateState(updateState); + if (_menu == null) + { + _pdaSystem.Log.Error("PDA state received before menu was created."); + return; + } + + _menu.UpdateState(updateState); } protected override void AttachCartridgeUI(Control cartridgeUIFragment, string? title) diff --git a/Content.Client/PDA/PdaMenu.xaml b/Content.Client/PDA/PdaMenu.xaml index 8b26860332d..8c9b4ae2ee6 100644 --- a/Content.Client/PDA/PdaMenu.xaml +++ b/Content.Client/PDA/PdaMenu.xaml @@ -67,14 +67,17 @@ Description="{Loc 'comp-pda-ui-ringtone-button-description'}"/> From c7234934d2604b46abe44fdf9224205a0b1e2bb8 Mon Sep 17 00:00:00 2001 From: PJBot Date: Fri, 13 Sep 2024 14:20:38 +0000 Subject: [PATCH 019/138] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 532c8ed1c01..0a40953d83f 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: ArkiveDev - changes: - - message: Railings can now be constructed in all 4 orientations. - type: Fix - id: 6865 - time: '2024-07-03T16:59:29.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29687 - author: Rinary changes: - message: Fixed radial menus overlapping where there's many icons. @@ -3918,3 +3911,11 @@ id: 7364 time: '2024-09-13T14:02:54.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/27624 +- author: ShadowCommander + changes: + - message: Fixed PDA sometimes showing uplink and music buttons when the PDA was + not able to use them. + type: Fix + id: 7365 + time: '2024-09-13T14:19:32.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/28373 From 3a83e1a8086a14415c2b44da33bb62c88e37d6c8 Mon Sep 17 00:00:00 2001 From: NotSoDamn <75203942+NotSoDana@users.noreply.github.com> Date: Fri, 13 Sep 2024 17:02:45 +0200 Subject: [PATCH 020/138] Added void cloak hood (#31061) * void hood * reshade * reshade x2 * Update hoods.yml --- .../Entities/Clothing/Head/hoods.yml | 17 +++++++++++++++++ .../Entities/Clothing/Neck/cloaks.yml | 8 ++++++++ .../Hoods/voidcloak.rsi/equipped-HELMET.png | Bin 0 -> 776 bytes .../Head/Hoods/voidcloak.rsi/icon.png | Bin 0 -> 316 bytes .../Head/Hoods/voidcloak.rsi/meta.json | 18 ++++++++++++++++++ 5 files changed, 43 insertions(+) create mode 100644 Resources/Textures/Clothing/Head/Hoods/voidcloak.rsi/equipped-HELMET.png create mode 100644 Resources/Textures/Clothing/Head/Hoods/voidcloak.rsi/icon.png create mode 100644 Resources/Textures/Clothing/Head/Hoods/voidcloak.rsi/meta.json diff --git a/Resources/Prototypes/Entities/Clothing/Head/hoods.yml b/Resources/Prototypes/Entities/Clothing/Head/hoods.yml index 82cff81c22b..1330d38f404 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/hoods.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/hoods.yml @@ -746,3 +746,20 @@ - state: coatybits-equipped-HELMET color: "#EBE216" - state: winterbits-equipped-HELMET + +- type: entity + parent: ClothingHeadBase + id: ClothingHeadHatHoodVoidCloak + name: void cloak hood + description: The hood of a void cloak. For those who have gone to the dark side of the force. + components: + - type: Sprite + sprite: Clothing/Head/Hoods/voidcloak.rsi + - type: Clothing + sprite: Clothing/Head/Hoods/voidcloak.rsi + - type: Tag + tags: + - WhitelistChameleon + - type: HideLayerClothing + slots: + - Hair diff --git a/Resources/Prototypes/Entities/Clothing/Neck/cloaks.yml b/Resources/Prototypes/Entities/Clothing/Neck/cloaks.yml index 555887b01db..02a8ec62b13 100644 --- a/Resources/Prototypes/Entities/Clothing/Neck/cloaks.yml +++ b/Resources/Prototypes/Entities/Clothing/Neck/cloaks.yml @@ -197,6 +197,14 @@ components: - type: Sprite sprite: Clothing/Neck/Cloaks/void.rsi + - type: ToggleableClothing + clothingPrototype: ClothingHeadHatHoodVoidCloak + requiredSlot: + - neck + slot: head + - type: ContainerContainer + containers: + toggleable-clothing: !type:ContainerSlot {} - type: TypingIndicatorClothing proto: alien diff --git a/Resources/Textures/Clothing/Head/Hoods/voidcloak.rsi/equipped-HELMET.png b/Resources/Textures/Clothing/Head/Hoods/voidcloak.rsi/equipped-HELMET.png new file mode 100644 index 0000000000000000000000000000000000000000..ba4a4d8b7fcfbf52fd110e0124ea6935263c7d45 GIT binary patch literal 776 zcmV+j1NZ!iP)Px%!bwCyRCt{2nlW$MKorOSMwPSE#c#D*q_M~b?6li)v)-8L`}+M`p(cpLD!Lv6fK{`meU9q@0D>?i z$0z-vqU&+9-hk)(2!i0Yy;6Z`7=@aUHo&S`Fb!kc=lMPy*O4;d3FT(1W=)fiZmv(K z9YL@q`inx$zHIUU($_K7gc4OqD)}P-E&w;Wxjs$Lh$6`*zo>l?q#2OHO}T?j!KYUi$_0h6S~2LR4pM=N|6c=zGG_WI?k7{E4wH>s{|0Qfcj zy_R+0*s z$h;aoQ2cuWtBxyWK>8g4&-Z8giZVe|htr6nsBB!a0rQd{g(2ecm^zdcq6)2*O4!tO zc)kzQFwm?w#OxrMAT)GWs^iFI|4780x427LfS+qS=~XuNw# zVhod*xsftpp5yCC{-Id1vw&>C!C;_8(Iukj62N3Nw#;frDtZnqv)a*06Zt~VTDC#p z_Rt{?CFPB>%rLnT4`H1zX)+AMFbu;m48t%C!!QiPx#_DMuRR9J=Wlf8<7E4K?XltqVTWcP`_AZ=q9H6SBj^^+X>#+;+?kJIE+~qkd^(mSIS2v(+O5_#8~YiLEda-HLq@g9gLFc=LjV3Lt1gVE6PJZ~edrznb|{5v;jdr$k Date: Fri, 13 Sep 2024 15:03:51 +0000 Subject: [PATCH 021/138] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 0a40953d83f..56b6078e12a 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Rinary - changes: - - message: Fixed radial menus overlapping where there's many icons. - type: Fix - id: 6866 - time: '2024-07-04T01:25:25.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29678 - author: Plykiya changes: - message: An object's physics properly returns to normal after being pulled. @@ -3919,3 +3912,10 @@ id: 7365 time: '2024-09-13T14:19:32.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/28373 +- author: Dezzzix + changes: + - message: Now you can wear a hood in void cloak + type: Add + id: 7366 + time: '2024-09-13T15:02:45.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/31061 From 115ed0cdb2214e58425af2906a15877b4422c2c0 Mon Sep 17 00:00:00 2001 From: Fildrance Date: Sat, 14 Sep 2024 01:49:27 +0300 Subject: [PATCH 022/138] Fix setmapatmos temperature argument Co-authored-by: pa.pecherskij --- Content.Server/Atmos/Commands/SetMapAtmosCommand.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Server/Atmos/Commands/SetMapAtmosCommand.cs b/Content.Server/Atmos/Commands/SetMapAtmosCommand.cs index 6f04cfb2da6..92dd64eeca5 100644 --- a/Content.Server/Atmos/Commands/SetMapAtmosCommand.cs +++ b/Content.Server/Atmos/Commands/SetMapAtmosCommand.cs @@ -54,7 +54,7 @@ public override void Execute(IConsoleShell shell, string argStr, string[] args) return; } - var mix = new GasMixture(Atmospherics.CellVolume) {Temperature = Math.Min(temp, Atmospherics.TCMB)}; + var mix = new GasMixture(Atmospherics.CellVolume) {Temperature = Math.Max(temp, Atmospherics.TCMB)}; for (var i = 0; i < Atmospherics.TotalNumberOfGases; i++) { if (args.Length == 3 + i) From 1a4a467a2e656d480922c71e35afe6be737f1bd1 Mon Sep 17 00:00:00 2001 From: PJBot Date: Fri, 13 Sep 2024 22:50:33 +0000 Subject: [PATCH 023/138] Automatic changelog update --- Resources/Changelog/Admin.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Resources/Changelog/Admin.yml b/Resources/Changelog/Admin.yml index d4d6e9e6abe..3951dd6e861 100644 --- a/Resources/Changelog/Admin.yml +++ b/Resources/Changelog/Admin.yml @@ -527,5 +527,12 @@ Entries: id: 65 time: '2024-09-08T07:28:43.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/30456 +- author: Fildrance + changes: + - message: The setmapatmos command now correctly uses its temperature argument + type: Fix + id: 66 + time: '2024-09-13T22:49:27.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/32125 Name: Admin Order: 1 From 8385de8769fe8835e9ed74641d5c42bae6dc125c Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Sat, 14 Sep 2024 01:58:54 +0200 Subject: [PATCH 024/138] Fix powered machines working unpowered if the panel is open. (#32135) --- Content.Client/Power/ActivatableUIRequiresPowerSystem.cs | 3 --- .../Power/EntitySystems/ActivatableUIRequiresPowerSystem.cs | 5 ----- 2 files changed, 8 deletions(-) diff --git a/Content.Client/Power/ActivatableUIRequiresPowerSystem.cs b/Content.Client/Power/ActivatableUIRequiresPowerSystem.cs index 5a082485a5a..a6a20958f53 100644 --- a/Content.Client/Power/ActivatableUIRequiresPowerSystem.cs +++ b/Content.Client/Power/ActivatableUIRequiresPowerSystem.cs @@ -18,9 +18,6 @@ protected override void OnActivate(Entity e return; } - if (TryComp(ent.Owner, out var panel) && panel.Open) - return; - _popup.PopupClient(Loc.GetString("base-computer-ui-component-not-powered", ("machine", ent.Owner)), args.User, args.User); args.Cancel(); } diff --git a/Content.Server/Power/EntitySystems/ActivatableUIRequiresPowerSystem.cs b/Content.Server/Power/EntitySystems/ActivatableUIRequiresPowerSystem.cs index 9fd824a3c49..a33bddcaa34 100644 --- a/Content.Server/Power/EntitySystems/ActivatableUIRequiresPowerSystem.cs +++ b/Content.Server/Power/EntitySystems/ActivatableUIRequiresPowerSystem.cs @@ -1,9 +1,7 @@ -using Content.Server.Power.Components; using Content.Shared.Power; using Content.Shared.Power.Components; using Content.Shared.Power.EntitySystems; using Content.Shared.UserInterface; -using Content.Shared.Wires; using ActivatableUISystem = Content.Shared.UserInterface.ActivatableUISystem; namespace Content.Server.Power.EntitySystems; @@ -26,9 +24,6 @@ protected override void OnActivate(Entity e return; } - if (TryComp(ent.Owner, out var panel) && panel.Open) - return; - args.Cancel(); } From beced35e17c6f7fc08e8109ba9dd8eee9f4ce70b Mon Sep 17 00:00:00 2001 From: PJBot Date: Sat, 14 Sep 2024 00:00:00 +0000 Subject: [PATCH 025/138] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 56b6078e12a..639ef9eb24a 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Plykiya - changes: - - message: An object's physics properly returns to normal after being pulled. - type: Fix - id: 6867 - time: '2024-07-04T01:29:07.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29694 - author: Plykiya changes: - message: You can now destroy portable flashers. @@ -3919,3 +3912,10 @@ id: 7366 time: '2024-09-13T15:02:45.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/31061 +- author: PJB3005 + changes: + - message: Fixed some powered machines working when unpowered if the panel is open. + type: Fix + id: 7367 + time: '2024-09-13T23:58:54.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/32135 From b11fdd5f0baa3e3a8e39c3335115fe56a53e9203 Mon Sep 17 00:00:00 2001 From: deltanedas <39013340+deltanedas@users.noreply.github.com> Date: Sat, 14 Sep 2024 00:51:51 +0000 Subject: [PATCH 026/138] network airlock AutoClose (#32124) * network airlock AutoClose * least stupid language * great language --------- Co-authored-by: deltanedas <@deltanedas:kde.org> --- Content.Server/Doors/Systems/AirlockSystem.cs | 6 ++++-- Content.Shared/Doors/Components/AirlockComponent.cs | 2 +- Content.Shared/Doors/Systems/SharedAirlockSystem.cs | 3 +++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Content.Server/Doors/Systems/AirlockSystem.cs b/Content.Server/Doors/Systems/AirlockSystem.cs index e9f1db13ffb..ca3d133bd05 100644 --- a/Content.Server/Doors/Systems/AirlockSystem.cs +++ b/Content.Server/Doors/Systems/AirlockSystem.cs @@ -35,9 +35,10 @@ private void OnAirlockInit(EntityUid uid, AirlockComponent component, ComponentI private void OnSignalReceived(EntityUid uid, AirlockComponent component, ref SignalReceivedEvent args) { - if (args.Port == component.AutoClosePort) + if (args.Port == component.AutoClosePort && component.AutoClose) { component.AutoClose = false; + Dirty(uid, component); } } @@ -84,10 +85,11 @@ private void OnActivate(EntityUid uid, AirlockComponent component, ActivateInWor return; } - if (component.KeepOpenIfClicked) + if (component.KeepOpenIfClicked && component.AutoClose) { // Disable auto close component.AutoClose = false; + Dirty(uid, component); } } } diff --git a/Content.Shared/Doors/Components/AirlockComponent.cs b/Content.Shared/Doors/Components/AirlockComponent.cs index b2fa7574f76..6577b1942ac 100644 --- a/Content.Shared/Doors/Components/AirlockComponent.cs +++ b/Content.Shared/Doors/Components/AirlockComponent.cs @@ -48,7 +48,7 @@ public sealed partial class AirlockComponent : Component /// /// Whether the airlock should auto close. This value is reset every time the airlock closes. /// - [ViewVariables(VVAccess.ReadWrite)] + [DataField, AutoNetworkedField] public bool AutoClose = true; /// diff --git a/Content.Shared/Doors/Systems/SharedAirlockSystem.cs b/Content.Shared/Doors/Systems/SharedAirlockSystem.cs index 5a6d45d9ec0..c0c274207b6 100644 --- a/Content.Shared/Doors/Systems/SharedAirlockSystem.cs +++ b/Content.Shared/Doors/Systems/SharedAirlockSystem.cs @@ -56,7 +56,10 @@ private void OnStateChanged(EntityUid uid, AirlockComponent component, DoorState // Make sure the airlock auto closes again next time it is opened if (args.State == DoorState.Closed) + { component.AutoClose = true; + Dirty(uid, component); + } } private void OnBeforeDoorOpened(EntityUid uid, AirlockComponent component, BeforeDoorOpenedEvent args) From 89fcda844913a079345276d04a933363ca6a5f0e Mon Sep 17 00:00:00 2001 From: qwerltaz <69696513+qwerltaz@users.noreply.github.com> Date: Sat, 14 Sep 2024 03:53:14 +0200 Subject: [PATCH 027/138] fix rcd blacklist (#32102) * fix rcd whitelist * terminal under shutters too --- Resources/Prototypes/RCD/rcd.yml | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/Resources/Prototypes/RCD/rcd.yml b/Resources/Prototypes/RCD/rcd.yml index 500b5f59bf9..88a99451cfa 100644 --- a/Resources/Prototypes/RCD/rcd.yml +++ b/Resources/Prototypes/RCD/rcd.yml @@ -95,7 +95,7 @@ prototype: Grille cost: 4 delay: 2 - collisionMask: FullTileMask + collisionMask: Impassable rotation: Fixed fx: EffectRCDConstruct2 @@ -108,7 +108,7 @@ prototype: Window cost: 3 delay: 2 - collisionMask: FullTileMask + collisionMask: Impassable rules: - IsWindow rotation: Fixed @@ -122,7 +122,7 @@ prototype: WindowDirectional cost: 2 delay: 1 - collisionMask: FullTileMask + collisionMask: Impassable collisionBounds: "-0.23,-0.49,0.23,-0.36" rules: - IsWindow @@ -137,7 +137,7 @@ prototype: ReinforcedWindow cost: 4 delay: 3 - collisionMask: FullTileMask + collisionMask: Impassable rules: - IsWindow rotation: User @@ -151,7 +151,7 @@ prototype: WindowReinforcedDirectional cost: 3 delay: 2 - collisionMask: FullTileMask + collisionMask: Impassable collisionBounds: "-0.23,-0.49,0.23,-0.36" rules: - IsWindow @@ -231,7 +231,6 @@ prototype: CableApcExtension cost: 1 delay: 0 - collisionMask: InteractImpassable rules: - MustBuildOnSubfloor rotation: Fixed @@ -245,7 +244,6 @@ prototype: CableMV cost: 1 delay: 0 - collisionMask: InteractImpassable rules: - MustBuildOnSubfloor rotation: Fixed @@ -259,7 +257,6 @@ prototype: CableHV cost: 1 delay: 0 - collisionMask: InteractImpassable rules: - MustBuildOnSubfloor rotation: Fixed @@ -273,8 +270,6 @@ prototype: CableTerminal cost: 1 delay: 0 - collisionMask: InteractImpassable - rules: - - MustBuildOnSubfloor + collisionMask: Impassable rotation: User - fx: EffectRCDConstruct0 \ No newline at end of file + fx: EffectRCDConstruct0 From 74888c86f29ae5da99355929cc43b3578fd5c25f Mon Sep 17 00:00:00 2001 From: lzk <124214523+lzk228@users.noreply.github.com> Date: Sat, 14 Sep 2024 03:53:39 +0200 Subject: [PATCH 028/138] fix aller at once desc (#32129) --- Resources/Prototypes/game_presets.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Prototypes/game_presets.yml b/Resources/Prototypes/game_presets.yml index efce3c4e24c..0804dc71540 100644 --- a/Resources/Prototypes/game_presets.yml +++ b/Resources/Prototypes/game_presets.yml @@ -52,7 +52,7 @@ - badidea - punishment name: aller-at-once-title - description: all-at-once-description + description: aller-at-once-description showInVote: false #Please god dont do this rules: - Nukeops From 9b168228e0c0d3f6d21e8a3b1d69015350364099 Mon Sep 17 00:00:00 2001 From: PJBot Date: Sat, 14 Sep 2024 01:54:20 +0000 Subject: [PATCH 029/138] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 639ef9eb24a..3618694af34 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Plykiya - changes: - - message: You can now destroy portable flashers. - type: Fix - id: 6868 - time: '2024-07-04T01:51:46.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29564 - author: EmoGarbage404 changes: - message: All nuclear operatives are now humans. @@ -3919,3 +3912,11 @@ id: 7367 time: '2024-09-13T23:58:54.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/32135 +- author: qwerltaz + changes: + - message: The RCD can now place grilles and windows under shutters and cables under + doors. + type: Fix + id: 7368 + time: '2024-09-14T01:53:14.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/32102 From f04de87ec4414f60b15f1aa7cf5dc846e0cd67d2 Mon Sep 17 00:00:00 2001 From: Alpha-Two <92269094+Alpha-Two@users.noreply.github.com> Date: Sat, 14 Sep 2024 12:28:35 +0100 Subject: [PATCH 030/138] Fix that space (#32149) Fixed the GODDAMN SPACE Co-authored-by: Alpha-Two --- Resources/Prototypes/Reagents/botany.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Resources/Prototypes/Reagents/botany.yml b/Resources/Prototypes/Reagents/botany.yml index 23d80f0e79b..e96d5be30c7 100644 --- a/Resources/Prototypes/Reagents/botany.yml +++ b/Resources/Prototypes/Reagents/botany.yml @@ -238,8 +238,8 @@ type: Rat shouldHave: false - !type:OrganType - type: Vox - shouldHave: false + type: Vox + shouldHave: false - !type:ReagentThreshold reagent: Ammonia min: 0.8 From ad5cb50a9e9b756645d69aeca550924789593fb8 Mon Sep 17 00:00:00 2001 From: deltanedas <39013340+deltanedas@users.noreply.github.com> Date: Sat, 14 Sep 2024 11:32:45 +0000 Subject: [PATCH 031/138] add gateway beacon for mapping (#32121) Co-authored-by: deltanedas <@deltanedas:kde.org> --- Resources/Locale/en-US/navmap-beacons/station-beacons.ftl | 1 + .../Entities/Objects/Devices/station_beacon.yml | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/Resources/Locale/en-US/navmap-beacons/station-beacons.ftl b/Resources/Locale/en-US/navmap-beacons/station-beacons.ftl index 6434311f21f..9d0919d102c 100644 --- a/Resources/Locale/en-US/navmap-beacons/station-beacons.ftl +++ b/Resources/Locale/en-US/navmap-beacons/station-beacons.ftl @@ -3,6 +3,7 @@ station-beacon-general = General station-beacon-command = Command station-beacon-bridge = Bridge station-beacon-vault = Vault +station-beacon-gateway = Gateway station-beacon-captain = Captain station-beacon-hop = HOP diff --git a/Resources/Prototypes/Entities/Objects/Devices/station_beacon.yml b/Resources/Prototypes/Entities/Objects/Devices/station_beacon.yml index b4e336b37dd..19eab391ac0 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/station_beacon.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/station_beacon.yml @@ -137,6 +137,14 @@ - type: NavMapBeacon defaultText: station-beacon-vault +- type: entity + parent: DefaultStationBeaconCommand + id: DefaultStationBeaconGateway + suffix: Gateway + components: + - type: NavMapBeacon + defaultText: station-beacon-gateway + - type: entity parent: DefaultStationBeaconCommand id: DefaultStationBeaconCaptainsQuarters From b68fcb6a4eb9254eb5ca73fb7066cfaebb887d80 Mon Sep 17 00:00:00 2001 From: SlamBamActionman <83650252+SlamBamActionman@users.noreply.github.com> Date: Sat, 14 Sep 2024 15:09:43 +0200 Subject: [PATCH 032/138] Add briefcase damage (#32063) Initial commit --- Resources/Prototypes/Entities/Objects/Misc/briefcases.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Resources/Prototypes/Entities/Objects/Misc/briefcases.yml b/Resources/Prototypes/Entities/Objects/Misc/briefcases.yml index 762204701cb..77ddcf0d983 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/briefcases.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/briefcases.yml @@ -12,6 +12,10 @@ - type: Tag tags: - Briefcase + - type: MeleeWeapon + damage: + types: + Blunt: 8 - type: entity parent: BriefcaseBase From 3250bb2aec12c0592d49d97dd90a8bbc6cdb3d7f Mon Sep 17 00:00:00 2001 From: PJBot Date: Sat, 14 Sep 2024 13:10:49 +0000 Subject: [PATCH 033/138] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 3618694af34..d8d384ce17e 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: EmoGarbage404 - changes: - - message: All nuclear operatives are now humans. - type: Tweak - id: 6869 - time: '2024-07-04T02:29:26.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29693 - author: metalgearsloth changes: - message: Made vox roundstart. @@ -3920,3 +3913,10 @@ id: 7368 time: '2024-09-14T01:53:14.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/32102 +- author: SlamBamActionman + changes: + - message: Briefcases can now be used as melee weapons. + type: Add + id: 7369 + time: '2024-09-14T13:09:43.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/32063 From 58ed124dc17ac785ba5db7c87ddd961174d82f96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82?= <123451459+JustArt1m@users.noreply.github.com> Date: Sat, 14 Sep 2024 17:55:13 +0300 Subject: [PATCH 034/138] New gauze customization (#30852) * Sprite&Meta * Marking_Prototype * Locale * Meta_copyright_change * Sprite_Change * New_Sprite * And_another_new_sprite * Change_Locale --- Resources/Locale/en-US/markings/gauze.ftl | 3 +++ .../Mobs/Customization/Markings/gauze.yml | 14 ++++++++++++++ .../Mobs/Customization/gauze.rsi/gauze_head.png | Bin 0 -> 409 bytes .../Mobs/Customization/gauze.rsi/meta.json | 6 +++++- 4 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 Resources/Textures/Mobs/Customization/gauze.rsi/gauze_head.png diff --git a/Resources/Locale/en-US/markings/gauze.ftl b/Resources/Locale/en-US/markings/gauze.ftl index f8bedc31957..7ed35a90ba1 100644 --- a/Resources/Locale/en-US/markings/gauze.ftl +++ b/Resources/Locale/en-US/markings/gauze.ftl @@ -46,6 +46,9 @@ marking-GauzeUpperLegRight = Gauze Thigh Wrap (Right) marking-GauzeBlindfold-gauze_blindfold = Gauze Blindfold marking-GauzeBlindfold = Gauze Blindfold +marking-GauzeHead-gauze_head = Gauze Head Wrap +marking-GauzeHead = Gauze Head Wrap + marking-GauzeLizardBlindfold-gauze_lizard_blindfold = Gauze Blindfold marking-GauzeLizardBlindfold = Gauze Blindfold diff --git a/Resources/Prototypes/Entities/Mobs/Customization/Markings/gauze.yml b/Resources/Prototypes/Entities/Mobs/Customization/Markings/gauze.yml index 2e3c9ddf46d..870a7cf7d75 100644 --- a/Resources/Prototypes/Entities/Mobs/Customization/Markings/gauze.yml +++ b/Resources/Prototypes/Entities/Mobs/Customization/Markings/gauze.yml @@ -222,6 +222,20 @@ - sprite: Mobs/Customization/gauze.rsi state: gauze_boxerwrap_l +- type: marking + id: GauzeHead + bodyPart: Head + markingCategory: Overlay + speciesRestriction: [Dwarf, Human, Reptilian, Arachnid, Moth] + coloring: + default: + type: + !type:SimpleColoring + color: "#FFFFFF" + sprites: + - sprite: Mobs/Customization/gauze.rsi + state: gauze_head + # Lizard Specific Markings - type: marking id: GauzeLizardLefteyePatch diff --git a/Resources/Textures/Mobs/Customization/gauze.rsi/gauze_head.png b/Resources/Textures/Mobs/Customization/gauze.rsi/gauze_head.png new file mode 100644 index 0000000000000000000000000000000000000000..713ae3d4bc5c31af482e1e95cc7ac7d8a8682b17 GIT binary patch literal 409 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7T#lEV080zaSW+oe0$3KAlhSQ)%m7G)|C=A*@+9`oi(m5SLE)!_U3>RwbvdbeKKecV`An&p`!3I~Yd`yS{9n>!I~@a! z)0gtBephTQkJbNd!Xn_nz=)S+syEwR!tECkXu1_kC9P`^TN9yKSWZe14qOb+-SX-GjHayFcDA2!Eqks}UT)Qonth zvr&aOJ{x~bXUd)tovZC^@9+c|uzaZzo@u_m3|c@o2M~k6rQpdR%G1@)Wt~$(695G7 Bo@4+3 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/gauze.rsi/meta.json b/Resources/Textures/Mobs/Customization/gauze.rsi/meta.json index 8d82ccab517..bd7d1ed4eb4 100644 --- a/Resources/Textures/Mobs/Customization/gauze.rsi/meta.json +++ b/Resources/Textures/Mobs/Customization/gauze.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Gauze sprites by Github KittenColony / Discord kittencolony (297865728374210561)", + "copyright": "Gauze sprites by Github KittenColony / Discord kittencolony (297865728374210561), gauze_head by github:DreamlyJack(624946166152298517)", "size": { "x": 32, "y": 32 @@ -142,6 +142,10 @@ { "name": "gauze_moth_lowerleg_l", "directions": 4 + }, + { + "name": "gauze_head", + "directions": 4 } ] } \ No newline at end of file From 378abeee959f5bfd5fce0230ada2b8ba0c15904d Mon Sep 17 00:00:00 2001 From: PJBot Date: Sat, 14 Sep 2024 14:56:20 +0000 Subject: [PATCH 035/138] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index d8d384ce17e..6a71e51b174 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: metalgearsloth - changes: - - message: Made vox roundstart. - type: Tweak - id: 6870 - time: '2024-07-04T07:11:02.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29704 - author: JIPDawg changes: - message: Changed the basic treatment module to include a Health Analyzer and removed @@ -3920,3 +3913,10 @@ id: 7369 time: '2024-09-14T13:09:43.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/32063 +- author: Just_Art + changes: + - message: Added a head gauze to customization. + type: Add + id: 7370 + time: '2024-09-14T14:55:13.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/30852 From d4ce1adac34c499121ee5fed4cf4d72c1c8d4bb5 Mon Sep 17 00:00:00 2001 From: deltanedas <39013340+deltanedas@users.noreply.github.com> Date: Sat, 14 Sep 2024 15:56:57 +0000 Subject: [PATCH 036/138] fix helmet parent (#32152) Co-authored-by: deltanedas <@deltanedas:kde.org> --- Resources/Prototypes/Entities/Clothing/Head/helmets.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Prototypes/Entities/Clothing/Head/helmets.yml b/Resources/Prototypes/Entities/Clothing/Head/helmets.yml index fafa66c8141..625ef7a0561 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/helmets.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/helmets.yml @@ -23,7 +23,7 @@ #Basic Helmet (Security Helmet) - type: entity - parent: [ClothingHeadBase, BaseRestrictedContraband] + parent: [ClothingHeadHelmetBase, BaseRestrictedContraband] id: ClothingHeadHelmetBasic name: helmet description: Standard security gear. Protects the head from impacts. From 98ca7c852982849a0948a6bd1f64ce61b9848e28 Mon Sep 17 00:00:00 2001 From: PJBot Date: Sat, 14 Sep 2024 15:58:04 +0000 Subject: [PATCH 037/138] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 6a71e51b174..c18265a523d 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: JIPDawg - changes: - - message: Changed the basic treatment module to include a Health Analyzer and removed - the dropper. - type: Tweak - id: 6871 - time: '2024-07-04T07:17:47.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29696 - author: PJB3005 changes: - message: Fixed flashlights and similar permanently getting stuck blinking. @@ -3920,3 +3912,10 @@ id: 7370 time: '2024-09-14T14:55:13.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/30852 +- author: deltanedas + changes: + - message: Fixed security's helmets not having any protection. + type: Fix + id: 7371 + time: '2024-09-14T15:56:57.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/32152 From 00650f16ec15c210a51cbc8ca32d7fcaeea678fc Mon Sep 17 00:00:00 2001 From: Ed <96445749+TheShuEd@users.noreply.github.com> Date: Sat, 14 Sep 2024 19:21:33 +0300 Subject: [PATCH 038/138] Dev mouse acorgillation (#32040) * Update dev_map.yml * real mouse returned --- Resources/Maps/Test/dev_map.yml | 2 +- .../Entities/Markers/Spawners/mobs.yml | 14 + .../Prototypes/Entities/Mobs/NPCs/pets.yml | 23 ++ .../Textures/Mobs/Pets/corgi.rsi/meta.json | 292 ++---------------- .../Mobs/Pets/corgi.rsi/real_mouse.png | Bin 0 -> 2084 bytes .../Mobs/Pets/corgi.rsi/real_mouse_dead.png | Bin 0 -> 733 bytes 6 files changed, 71 insertions(+), 260 deletions(-) create mode 100644 Resources/Textures/Mobs/Pets/corgi.rsi/real_mouse.png create mode 100644 Resources/Textures/Mobs/Pets/corgi.rsi/real_mouse_dead.png diff --git a/Resources/Maps/Test/dev_map.yml b/Resources/Maps/Test/dev_map.yml index ce735e7318f..75511b17604 100644 --- a/Resources/Maps/Test/dev_map.yml +++ b/Resources/Maps/Test/dev_map.yml @@ -5070,7 +5070,7 @@ entities: - type: Transform pos: 3.5,7.5 parent: 179 -- proto: SpawnMobMouse +- proto: SpawnMobCorgiMouse entities: - uid: 1050 components: diff --git a/Resources/Prototypes/Entities/Markers/Spawners/mobs.yml b/Resources/Prototypes/Entities/Markers/Spawners/mobs.yml index cb06b39998f..52c2c326896 100644 --- a/Resources/Prototypes/Entities/Markers/Spawners/mobs.yml +++ b/Resources/Prototypes/Entities/Markers/Spawners/mobs.yml @@ -48,6 +48,20 @@ - MobCorgiLisa - MobCorgiIanPup +- type: entity + name: Dev Mouse Spawner + id: SpawnMobCorgiMouse + suffix: Admeme + parent: MarkerBase + components: + - type: Sprite + layers: + - state: green + - state: ai + - type: ConditionalSpawner + prototypes: + - MobCorgiMouse + - type: entity name: Possum Morty Spawner id: SpawnMobPossumMorty diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml b/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml index 6338a294e77..ebc1b80541c 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml @@ -85,6 +85,29 @@ proper: true gender: female +- type: entity + name: real mouse + parent: MobCorgiIan + id: MobCorgiMouse + description: It's 100% a real hungry mouse. + components: + - type: Sprite + layers: + - map: ["enum.DamageStateVisualLayers.Base"] + state: real_mouse + - type: DamageStateVisuals + states: + Alive: + Base: real_mouse + Critical: + Base: real_mouse_dead + Dead: + Base: real_mouse_dead + - type: Grammar + attributes: + proper: true + gender: female + - type: entity name: Puppy Ian parent: MobCorgiPuppy diff --git a/Resources/Textures/Mobs/Pets/corgi.rsi/meta.json b/Resources/Textures/Mobs/Pets/corgi.rsi/meta.json index 3a540931649..0e36d32316f 100644 --- a/Resources/Textures/Mobs/Pets/corgi.rsi/meta.json +++ b/Resources/Textures/Mobs/Pets/corgi.rsi/meta.json @@ -5,207 +5,60 @@ "y": 32 }, "license": "CC-BY-SA-3.0", - "copyright": "https://github.com/tgstation/tgstation/commit/53d1f1477d22a11a99c6c6924977cd431075761b , cerberus by Alekshhh", + "copyright": "https://github.com/tgstation/tgstation/commit/53d1f1477d22a11a99c6c6924977cd431075761b , cerberus by Alekshhh, real mouse by TheShuEd", "states": [ { "name": "corgi", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] + "directions": 4 }, { "name": "corgi_rest", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] + "directions": 4 }, { - "name": "corgi_dead", - "delays": [ - [ - 1 - ] - ] + "name": "corgi_dead" }, { "name": "ian", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] + "directions": 4 }, { - "name": "ian_dead", - "delays": [ - [ - 1 - ] - ] + "name": "ian_dead" }, { - "name": "corgi_deadcollar", - "delays": [ - [ - 1 - ] - ] + "name": "corgi_deadcollar" }, { - "name": "corgi_deadtag", - "delays": [ - [ - 1 - ] - ] + "name": "corgi_deadtag" }, { "name": "ian_shaved", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] + "directions": 4 }, { - "name": "ian_shaved_dead", - "delays": [ - [ - 1 - ] - ] + "name": "ian_shaved_dead" }, { "name": "corgicollar", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] + "directions": 4 }, { "name": "corgitag", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] + "directions": 4 }, { "name": "lisa", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] + "directions": 4 }, { - "name": "lisa_dead", - "delays": [ - [ - 1 - ] - ] + "name": "lisa_dead" }, { "name": "lisa_shaved", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] + "directions": 4 }, { - "name": "lisa_shaved_dead", - "delays": [ - [ - 1 - ] - ] + "name": "lisa_shaved_dead" }, { "name": "narsian", @@ -238,12 +91,7 @@ ] }, { - "name": "old_ian_dead", - "delays": [ - [ - 1 - ] - ] + "name": "old_ian_dead" }, { "name": "old_ian_shaved", @@ -268,116 +116,42 @@ ] }, { - "name": "old_ian_shaved_dead", - "delays": [ - [ - 1 - ] - ] + "name": "old_ian_shaved_dead" }, { "name": "puppy", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] + "directions": 4 }, { - "name": "puppy_dead", - "delays": [ - [ - 1 - ] - ] + "name": "puppy_dead" }, { - "name": "puppy_deadcollar", - "delays": [ - [ - 1 - ] - ] + "name": "puppy_deadcollar" }, { - "name": "puppy_deadtag", - "delays": [ - [ - 1 - ] - ] + "name": "puppy_deadtag" }, { "name": "puppy_shaved", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] + "directions": 4 }, { - "name": "puppy_shaved_dead", - "delays": [ - [ - 1 - ] - ] + "name": "puppy_shaved_dead" }, { "name": "puppycollar", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] + "directions": 4 }, { "name": "puppytag", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] + "directions": 4 + }, + { + "name": "real_mouse", + "directions": 4 + }, + { + "name": "real_mouse_dead" } ] } diff --git a/Resources/Textures/Mobs/Pets/corgi.rsi/real_mouse.png b/Resources/Textures/Mobs/Pets/corgi.rsi/real_mouse.png new file mode 100644 index 0000000000000000000000000000000000000000..2983063c4fd885579acfe4f39ea30759330e03eb GIT binary patch literal 2084 zcmV+<2;29GP)Px+-bqA3RCt{2nr&!X*BO8xZPkxKrw=Q{t(c{FklPlI)b|2toZ=jOJX@*+!%~wv0+Q9O_Vm) z2mVu>aQ8z#H}~qx_sUn>kLm$)ea}65-}AobocEl2-vc#j)c7)E(OdEQxi@8i!Qe#z z4)=8dkiHwovDrhhXFGrN8{P8t>c4+ENIIPbVABuZQ1pNP!CL@095x==-KSgsSBx}b zFnE#P?rrpTZ&QqgoD)htGn;feOZ(n^H2azqqd))PEt-8zwC~-gI7cs!=&dLWe7bQL zvLyjb7Z|$jn;tB31HIi;)d`u{6aXHtoA}sSJYKh^+z7fIaJa9FpZ@x<{O)DAarbMq zwY3%0IW_(nJ2uA|3Qu#muZx{yV}=`Kgt~gC=2{7crodl*{}XQ!7Wml1IrB7fMc??pTHV8{WG z3vO<=n}&u4B9RE~bzkTF`SVDUgxl?AFnE!lhyKZt3rVA*%hG>(Mp9dc+hL(ZrL{0{V&J}R{e~PMgzkIN4Lso0wSWjP{f`-V(rvooYVMDn<(FIB zWtY9>WQzFM5`1fqE}4e5s$suXZuT`{KQIcQ1VR8wk^sn@dX7&fX6PPXHEkQ5uYWy^ z=+_+t!+xtQc3c8Ul9WF+9}%4k-_R7$yW^^>cM^{+ z84+y=ySD{fGQ}qo4&EVFF}xi%ybJ=+ndkpC%Rn zh$rqS*DIGlHY%zj=5Eh0cYEglroTpw8Z~Ovs8OTFdW8K}dF+s@=4_`H3r4b3#={KqfXtHnW1mVcSrn z!+xvmaM;LZR;u>Bv7+2yDb%@xEmFh7a%SZGj}+<*Zn11`u_Q_65Ya^IC0vryT zCU>x$OtI(fm@<4rp&_|-lT&WpuVBIJzKn96P^xX^Mp01*%-x+dGLT6C5?i(Wz z=(U_V^PcX54X4VF}v&8)DTOlcfZjovRMD_?J^ zgOh^Arv`~9?iB5al2f3V$Asc^I!ipZq&Na{PSJS3Gswt6S4F)q2n2d9BL`iYQBYU! zRE!md$74&%l2>eWmg;>dvk%DM;n@$2a_hB5zWe8U7IhuLDEbQoyY`LRPT`RPB+D|MHXsj_DVO6~-^hgU6O|B^i4c9ahJ?*Ij#xYR9U<4qluIFsrUnME+msFsp8j8Z~NssrfI5?Px%mq|oHR9J=Wl|M`qVHn1LHL{WGT?b1r?UiUwjT7-7VE}_@TrdtUjR`3Wi=@OD zCtO{0;!*|(L}E-j;2?I;1T?Z>Km`Yh$t~KFG}K7jYuFghLGHLKz2h27T>5PH-Sge^ zywCT3??Dqy{AUFGkW@8gL?dkgGGwHs)f)^P4IKctS2_W@9H z6LhRRAQNvf{BQwJF4U0#fSz3^6qd+k^NtS>q<5{DMNzQ07g(n#x08wI4Liq(k!wGA9)YT+jNZv@SRA$1 ziiHwFuoZw%SV9Q45|!Jn%B#fz&YV5(s^O~#^z6Fh*)9?aOO_Egoc#WTXrv8QO&#b5 zR|Be=G7^bFNA+F^g(XB$pjar?EWj;=Llf|-z8WzlQgb~hce?KJbp-XG+Mp@Eu<)*C z6CQdEgL3DA6zai`)%WDGd6Ma8HE*1!0Zr3T`p3a`1^uAy z%|Edo+qY>J`-W(85L;)DSd7atW=X_n=U}(C+{Fuzu;a83g z_oTUoRS$a!lz-(|`&|kEtR+VP$i#OHfcY`mA{Ps#njQbo2FwKP7)b91GHe*;UoNIZ z8rFDrc#h(M^lqSBt{? Date: Sat, 14 Sep 2024 16:27:05 +0000 Subject: [PATCH 039/138] add test for lathe recipes having results (#32100) * add test for lathe recipes having results * id --------- Co-authored-by: deltanedas <@deltanedas:kde.org> --- .../Tests/ResearchTest.cs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Content.IntegrationTests/Tests/ResearchTest.cs b/Content.IntegrationTests/Tests/ResearchTest.cs index 7ae29a79ffd..f50e6111da3 100644 --- a/Content.IntegrationTests/Tests/ResearchTest.cs +++ b/Content.IntegrationTests/Tests/ResearchTest.cs @@ -98,4 +98,24 @@ await server.WaitAssertion(() => await pair.CleanReturnAsync(); } + + [Test] + public async Task AllLatheRecipesValidTest() + { + await using var pair = await PoolManager.GetServerClient(); + + var server = pair.Server; + var proto = server.ResolveDependency(); + + Assert.Multiple(() => + { + foreach (var recipe in proto.EnumeratePrototypes()) + { + if (recipe.Result == null) + Assert.That(recipe.ResultReagents, Is.Not.Null, $"Recipe '{recipe.ID}' has no result or result reagents."); + } + }); + + await pair.CleanReturnAsync(); + } } From 00e62b6c2201ce96b5769c88f27946b374fd646c Mon Sep 17 00:00:00 2001 From: eoineoineoin Date: Sat, 14 Sep 2024 17:28:33 +0100 Subject: [PATCH 040/138] Allow ghosts to read books (#32151) Co-authored-by: Eoin Mcloughlin --- Resources/Prototypes/Entities/Objects/Misc/books.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/Resources/Prototypes/Entities/Objects/Misc/books.yml b/Resources/Prototypes/Entities/Objects/Misc/books.yml index 29424074940..15ecd5d2a80 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/books.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/books.yml @@ -22,6 +22,7 @@ contentSize: 12000 - type: ActivatableUI key: enum.PaperUiKey.Key + requiresComplex: false - type: UserInterface interfaces: enum.PaperUiKey.Key: From dea27810472460d4f697b450a54d8cd0e1d30796 Mon Sep 17 00:00:00 2001 From: eoineoineoin Date: Sat, 14 Sep 2024 17:29:05 +0100 Subject: [PATCH 041/138] Fix some issues with pulling system (#32145) Joints were created with pivots at object origin, causing unintuitive behaviour when an object was not centered on the origin. Now puts the pivots at the COM. Joint limits were set based on fractions of the union of the AABB of objects, which did not make geometric sense. Now uses the pivot length with an additional [arbitrary] length. Joints were created with a very low spring stiffness, which had a negligible effect most of the time but caused very unintuitive behaviour when the pulled object had a low mass (#28028) - disable the spring limit, and just use the hard min/max limits. Co-authored-by: Eoin Mcloughlin --- .../Movement/Pulling/Systems/PullingSystem.cs | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs b/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs index 5f35adb3337..6392956d632 100644 --- a/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs +++ b/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs @@ -438,7 +438,7 @@ public bool TryStartPull(EntityUid pullerUid, EntityUid pullableUid, if (!CanPull(pullerUid, pullableUid)) return false; - if (!HasComp(pullerUid) || !TryComp(pullableUid, out PhysicsComponent? pullablePhysics)) + if (!TryComp(pullerUid, out PhysicsComponent? pullerPhysics) || !TryComp(pullableUid, out PhysicsComponent? pullablePhysics)) return false; // Ensure that the puller is not currently pulling anything. @@ -485,17 +485,19 @@ public bool TryStartPull(EntityUid pullerUid, EntityUid pullableUid, // joint state handling will manage its own state if (!_timing.ApplyingState) { - // Joint startup - var union = _physics.GetHardAABB(pullerUid).Union(_physics.GetHardAABB(pullableUid, body: pullablePhysics)); - var length = Math.Max(union.Size.X, union.Size.Y) * 0.75f; - - var joint = _joints.CreateDistanceJoint(pullableUid, pullerUid, id: pullableComp.PullJointId); + var joint = _joints.CreateDistanceJoint(pullableUid, pullerUid, + pullablePhysics.LocalCenter, pullerPhysics.LocalCenter, + id: pullableComp.PullJointId); joint.CollideConnected = false; // This maximum has to be there because if the object is constrained too closely, the clamping goes backwards and asserts. - joint.MaxLength = Math.Max(1.0f, length); - joint.Length = length * 0.75f; + // Internally, the joint length has been set to the distance between the pivots. + // Add an additional 15cm (pretty arbitrary) to the maximum length for the hard limit. + joint.MaxLength = joint.Length + 0.15f; joint.MinLength = 0f; - joint.Stiffness = 1f; + // Set the spring stiffness to zero. The joint won't have any effect provided + // the current length is beteen MinLength and MaxLength. At those limits, the + // joint will have infinite stiffness. + joint.Stiffness = 0f; _physics.SetFixedRotation(pullableUid, pullableComp.FixedRotationOnPull, body: pullablePhysics); } From 26addfe7a322039bff60b91232ecfa2cdd1a4df0 Mon Sep 17 00:00:00 2001 From: PJBot Date: Sat, 14 Sep 2024 16:29:39 +0000 Subject: [PATCH 042/138] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index c18265a523d..794bf7c251a 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: PJB3005 - changes: - - message: Fixed flashlights and similar permanently getting stuck blinking. - type: Fix - id: 6872 - time: '2024-07-04T08:02:43.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29457 - author: Jezithyr changes: - message: All species except for Vox can now be played as Nukies. (Vox will be @@ -3919,3 +3912,10 @@ id: 7371 time: '2024-09-14T15:56:57.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/32152 +- author: eoineoineoin + changes: + - message: Ghosts can now read books. + type: Add + id: 7372 + time: '2024-09-14T16:28:33.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/32151 From 7d4ae6762878fc476b17c9b7a979bbbdf0f41543 Mon Sep 17 00:00:00 2001 From: Errant <35878406+Errant-4@users.noreply.github.com> Date: Sat, 14 Sep 2024 18:34:01 +0200 Subject: [PATCH 043/138] Vox LoneOp loadout fix (#31641) oh shit here we go again --- .../Locale/en-US/preferences/loadout-groups.ftl | 1 + Resources/Prototypes/GameRules/events.yml | 3 +++ Resources/Prototypes/GameRules/roundstart.yml | 12 ++++++------ .../Loadouts/Miscellaneous/survival.yml | 17 +++++++++++++++++ .../Prototypes/Loadouts/loadout_groups.yml | 10 +++++++++- Resources/Prototypes/Loadouts/role_loadouts.yml | 7 +++++++ Resources/Prototypes/Roles/Antags/nukeops.yml | 3 +-- 7 files changed, 44 insertions(+), 9 deletions(-) diff --git a/Resources/Locale/en-US/preferences/loadout-groups.ftl b/Resources/Locale/en-US/preferences/loadout-groups.ftl index 92c3bb9d61e..79b49140923 100644 --- a/Resources/Locale/en-US/preferences/loadout-groups.ftl +++ b/Resources/Locale/en-US/preferences/loadout-groups.ftl @@ -15,6 +15,7 @@ loadout-group-survival-syndicate = Github is forcing me to write text that is li loadout-group-breath-tool = Species-dependent breath tools loadout-group-tank-harness = Species-specific survival equipment loadout-group-EVA-tank = Species-specific gas tank +loadout-group-pocket-tank-double = Species-specific double emergency tank in pocket loadout-group-survival-mime = Mime Survival Box # Command diff --git a/Resources/Prototypes/GameRules/events.yml b/Resources/Prototypes/GameRules/events.yml index 773f8946bfb..2281b3c5b01 100644 --- a/Resources/Prototypes/GameRules/events.yml +++ b/Resources/Prototypes/GameRules/events.yml @@ -443,6 +443,9 @@ max: 1 pickPlayer: false startingGear: SyndicateLoneOperativeGearFull + roleLoadout: + - RoleSurvivalNukie + components: - type: NukeOperative - type: RandomMetadata diff --git a/Resources/Prototypes/GameRules/roundstart.yml b/Resources/Prototypes/GameRules/roundstart.yml index 1659290ff38..caf2ca7945c 100644 --- a/Resources/Prototypes/GameRules/roundstart.yml +++ b/Resources/Prototypes/GameRules/roundstart.yml @@ -73,7 +73,7 @@ parent: BaseGameRule id: BaseNukeopsRule components: - - type: RandomMetadata #this generates the random operation name cuz it's cool. + - type: RandomMetadata #this generates the random operation name cuz it's cool. nameSegments: - operationPrefix - operationSuffix @@ -104,7 +104,7 @@ spawnerPrototype: SpawnPointNukeopsCommander startingGear: SyndicateCommanderGearFull roleLoadout: - - RoleSurvivalSyndicate + - RoleSurvivalNukie components: - type: NukeOperative - type: RandomMetadata @@ -122,7 +122,7 @@ spawnerPrototype: SpawnPointNukeopsMedic startingGear: SyndicateOperativeMedicFull roleLoadout: - - RoleSurvivalSyndicate + - RoleSurvivalNukie components: - type: NukeOperative - type: RandomMetadata @@ -142,7 +142,7 @@ playerRatio: 10 startingGear: SyndicateOperativeGearFull roleLoadout: - - RoleSurvivalSyndicate + - RoleSurvivalNukie components: - type: NukeOperative - type: RandomMetadata @@ -319,8 +319,8 @@ tableId: SpaceTrafficControlTable - type: entity - id: SpaceTrafficControlFriendlyEventScheduler - parent: BaseGameRule + id: SpaceTrafficControlFriendlyEventScheduler + parent: BaseGameRule components: - type: BasicStationEventScheduler minimumTimeUntilFirstEvent: 1200 # 20 mins diff --git a/Resources/Prototypes/Loadouts/Miscellaneous/survival.yml b/Resources/Prototypes/Loadouts/Miscellaneous/survival.yml index c84caeb99da..10543e6ea76 100644 --- a/Resources/Prototypes/Loadouts/Miscellaneous/survival.yml +++ b/Resources/Prototypes/Loadouts/Miscellaneous/survival.yml @@ -188,6 +188,23 @@ equipment: suitstorage: OxygenTankFilled +# Species-appropriate Double Emergency Tank in Pocket 1 +- type: loadout + id: LoadoutSpeciesPocketDoubleNitrogen + effects: + - !type:GroupLoadoutEffect + proto: NitrogenBreather + equipment: + pocket1: DoubleEmergencyNitrogenTankFilled + +- type: loadout + id: LoadoutSpeciesPocketDoubleOxygen + effects: + - !type:GroupLoadoutEffect + proto: OxygenBreather + equipment: + pocket1: DoubleEmergencyOxygenTankFilled + # Tank Harness - type: loadout id: LoadoutTankHarness diff --git a/Resources/Prototypes/Loadouts/loadout_groups.yml b/Resources/Prototypes/Loadouts/loadout_groups.yml index cff9a4f6365..fe17ea0fffc 100644 --- a/Resources/Prototypes/Loadouts/loadout_groups.yml +++ b/Resources/Prototypes/Loadouts/loadout_groups.yml @@ -61,6 +61,14 @@ - LoadoutSpeciesEVANitrogen - LoadoutSpeciesEVAOxygen +- type: loadoutGroup + id: GroupPocketTankDouble + name: loadout-group-pocket-tank-double + hidden: true + loadouts: + - LoadoutSpeciesPocketDoubleNitrogen + - LoadoutSpeciesPocketDoubleOxygen + # Command - type: loadoutGroup id: CaptainHead @@ -488,7 +496,7 @@ loadouts: - MimeSuspendersRed - MimeSuspendersBlack - + - type: loadoutGroup id: SurvivalMime name: loadout-group-survival-mime diff --git a/Resources/Prototypes/Loadouts/role_loadouts.yml b/Resources/Prototypes/Loadouts/role_loadouts.yml index e98676fc622..25b43fc22a7 100644 --- a/Resources/Prototypes/Loadouts/role_loadouts.yml +++ b/Resources/Prototypes/Loadouts/role_loadouts.yml @@ -569,6 +569,13 @@ - GroupSpeciesBreathTool - GroupTankHarness +- type: roleLoadout + id: RoleSurvivalNukie + groups: + - SurvivalSyndicate + - GroupSpeciesBreathTool + - GroupPocketTankDouble + - type: roleLoadout id: RoleSurvivalEVA groups: diff --git a/Resources/Prototypes/Roles/Antags/nukeops.yml b/Resources/Prototypes/Roles/Antags/nukeops.yml index 52d422876f7..8f1094802c7 100644 --- a/Resources/Prototypes/Roles/Antags/nukeops.yml +++ b/Resources/Prototypes/Roles/Antags/nukeops.yml @@ -50,7 +50,6 @@ outerClothing: ClothingOuterHardsuitSyndie shoes: ClothingShoesBootsCombatFilled id: SyndiPDA - pocket1: DoubleEmergencyOxygenTankFilled pocket2: PlushieCarp belt: ClothingBeltMilitaryWebbing storage: @@ -74,7 +73,7 @@ neck: SyndicateWhistle outerClothing: ClothingOuterHardsuitSyndieCommander inhand: - - NukeOpsDeclarationOfWar + - NukeOpsDeclarationOfWar #Nuclear Operative Medic Gear - type: startingGear From def864db303a04c0693d16abf29fb5b6c6375d41 Mon Sep 17 00:00:00 2001 From: PJBot Date: Sat, 14 Sep 2024 16:35:07 +0000 Subject: [PATCH 044/138] Automatic changelog update --- Resources/Changelog/Changelog.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 794bf7c251a..858696cec5c 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: Jezithyr - changes: - - message: All species except for Vox can now be played as Nukies. (Vox will be - enabled when load out code supports them) - type: Tweak - id: 6873 - time: '2024-07-05T07:59:16.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29707 - author: metalgearsloth changes: - message: Shuttle map buttons will show up faster. @@ -3919,3 +3911,11 @@ id: 7372 time: '2024-09-14T16:28:33.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/32151 +- author: Errant + changes: + - message: Lone Ops nukies now spawn with the appropriate species-specific survival + gear. + type: Fix + id: 7373 + time: '2024-09-14T16:34:01.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/31641 From baf9bb9d85f1cea7eaea8ce5e09b0bbe76c3cecb Mon Sep 17 00:00:00 2001 From: Plykiya <58439124+Plykiya@users.noreply.github.com> Date: Sat, 14 Sep 2024 10:19:32 -0700 Subject: [PATCH 045/138] Add snakes to vent spawn event (#32070) Add snakes to vents --- Resources/Prototypes/GameRules/events.yml | 61 +++++++++++++++-------- 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/Resources/Prototypes/GameRules/events.yml b/Resources/Prototypes/GameRules/events.yml index 2281b3c5b01..dc44915f53d 100644 --- a/Resources/Prototypes/GameRules/events.yml +++ b/Resources/Prototypes/GameRules/events.yml @@ -19,6 +19,7 @@ - id: RandomSentience - id: SlimesSpawn - id: SolarFlare + - id: SnakeSpawn - id: SpiderClownSpawn - id: SpiderSpawn - id: VentClog @@ -35,36 +36,35 @@ - id: SleeperAgents - id: ZombieOutbreak - - type: entity id: BaseStationEvent parent: BaseGameRule abstract: true components: - - type: GameRule - delay: - min: 10 - max: 20 + - type: GameRule + delay: + min: 10 + max: 20 - type: entity id: BaseStationEventShortDelay parent: BaseGameRule abstract: true components: - - type: GameRule - delay: - min: 10 - max: 20 + - type: GameRule + delay: + min: 10 + max: 20 - type: entity id: BaseStationEventLongDelay parent: BaseGameRule abstract: true components: - - type: GameRule - delay: - min: 40 - max: 60 + - type: GameRule + delay: + min: 40 + max: 60 - type: entity id: AnomalySpawn @@ -286,7 +286,7 @@ startAudio: path: /Audio/Announcements/power_off.ogg params: - volume: -4 + volume: -4 duration: 60 maxDuration: 120 - type: PowerGridCheckRule @@ -354,6 +354,27 @@ - id: MobAdultSlimesYellowAngry prob: 0.02 +- type: entity + id: SnakeSpawn + parent: BaseStationEventShortDelay + components: + - type: StationEvent + startAnnouncement: station-event-vent-creatures-start-announcement + startAudio: + path: /Audio/Announcements/attention.ogg + earliestStart: 20 + minimumPlayers: 15 + weight: 5 + duration: 60 + - type: VentCrittersRule + entries: + - id: MobPurpleSnake + prob: 0.02 + - id: MobSmallPurpleSnake + prob: 0.02 + - id: MobCobraSpace + prob: 0.02 + - type: entity id: SpiderSpawn parent: BaseStationEventShortDelay @@ -518,9 +539,9 @@ id: MimicVendorRule parent: BaseGameRule components: - - type: StationEvent - earliestStart: 0 - minimumPlayers: 20 - maxOccurrences: 1 # this event has diminishing returns on interesting-ness, so we cap it - weight: 5 - - type: MobReplacementRule + - type: StationEvent + earliestStart: 0 + minimumPlayers: 20 + maxOccurrences: 1 # this event has diminishing returns on interesting-ness, so we cap it + weight: 5 + - type: MobReplacementRule From c1243a6c631f4d621c1d003e7e3e1c9a67d04f10 Mon Sep 17 00:00:00 2001 From: PJBot Date: Sat, 14 Sep 2024 17:20:38 +0000 Subject: [PATCH 046/138] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 858696cec5c..7276b3e3787 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: metalgearsloth - changes: - - message: Shuttle map buttons will show up faster. - type: Tweak - id: 6874 - time: '2024-07-06T03:51:55.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29757 - author: JIPDawg changes: - message: Added Late join CryoSleepers to Origin. @@ -3919,3 +3912,10 @@ id: 7373 time: '2024-09-14T16:34:01.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/31641 +- author: Plykiya + changes: + - message: The vent spawn event now has a chance to spawn snakes. + type: Add + id: 7374 + time: '2024-09-14T17:19:32.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/32070 From 20914fea367289c36e9988f6c22ec802a74065b8 Mon Sep 17 00:00:00 2001 From: BIGZi0348 <118811750+BIGZi0348@users.noreply.github.com> Date: Sat, 14 Sep 2024 22:37:41 +0300 Subject: [PATCH 047/138] Moved hardcoded string "PEOPLE" to Loc.GetString() (#32164) --- Content.Server/StationEvents/Events/IonStormRule.cs | 4 +++- Resources/Locale/en-US/station-events/events/ion-storm.ftl | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Content.Server/StationEvents/Events/IonStormRule.cs b/Content.Server/StationEvents/Events/IonStormRule.cs index 7a959eb1e35..805549439ba 100644 --- a/Content.Server/StationEvents/Events/IonStormRule.cs +++ b/Content.Server/StationEvents/Events/IonStormRule.cs @@ -235,6 +235,8 @@ private string GenerateLaw() if (plural) feeling = feelingPlural; + var subjects = RobustRandom.Prob(0.5f) ? objectsThreats : Loc.GetString("ion-storm-people"); + // message logic!!! return RobustRandom.Next(0, 36) switch { @@ -266,7 +268,7 @@ private string GenerateLaw() 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)), + 29 => Loc.GetString("ion-storm-law-crew-only-subjects", ("adjective", adjective), ("subjects", subjects), ("part", part)), 30 => Loc.GetString("ion-storm-law-crew-must-do", ("must", must), ("part", part)), 31 => Loc.GetString("ion-storm-law-crew-must-have", ("adjective", adjective), ("objects", objects), ("part", part)), 32 => Loc.GetString("ion-storm-law-crew-must-eat", ("who", who), ("adjective", adjective), ("food", food), ("part", part)), diff --git a/Resources/Locale/en-US/station-events/events/ion-storm.ftl b/Resources/Locale/en-US/station-events/events/ion-storm.ftl index 28192d96637..02be271cdf2 100644 --- a/Resources/Locale/en-US/station-events/events/ion-storm.ftl +++ b/Resources/Locale/en-US/station-events/events/ion-storm.ftl @@ -9,6 +9,7 @@ ion-storm-the-job = THE {$job} ion-storm-clowns = CLOWNS ion-storm-heads = HEADS OF STAFF ion-storm-crew = CREW +ion-storm-people = PEOPLE ion-storm-adjective-things = {$adjective} THINGS ion-storm-x-and-y = {$x} AND {$y} From faaa2b3e444ea241cd1b698d9c5a4ae8bfa4336f Mon Sep 17 00:00:00 2001 From: lzk <124214523+lzk228@users.noreply.github.com> Date: Sat, 14 Sep 2024 22:40:38 +0200 Subject: [PATCH 048/138] reinforce command intercom (#32169) * secure command intercom * Update intercom.yml --- .../Structures/Wallmounts/intercom.yml | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/intercom.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/intercom.yml index 07b29b72259..ef3546981f9 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/intercom.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/intercom.yml @@ -205,6 +205,19 @@ - type: WiresPanel open: false +- type: entity + id: BaseIntercomSecure + parent: Intercom + abstract: true + components: + - type: WiresPanel + openDelay: 5 + - type: WiresPanelSecurity + examine: wires-panel-component-on-examine-security-level2 + wiresAccessible: false + - type: Construction + node: intercomReinforced + - type: entity id: IntercomCommon parent: Intercom @@ -219,8 +232,9 @@ - type: entity id: IntercomCommand - parent: Intercom + parent: BaseIntercomSecure suffix: Command + description: An intercom. It's been reinforced with metal. components: - type: ContainerFill containers: @@ -271,17 +285,10 @@ - type: entity id: IntercomSecurity - parent: Intercom + parent: BaseIntercomSecure suffix: Security description: An intercom. It's been reinforced with metal from security helmets, making it a bitch-and-a-half to open. components: - - type: WiresPanel - openDelay: 5 - - type: WiresPanelSecurity - examine: wires-panel-component-on-examine-security-level2 - wiresAccessible: false - - type: Construction - node: intercomReinforced - type: ContainerFill containers: board: From 77e6bf993bca6b6abccae1063c4e5a58742c7e59 Mon Sep 17 00:00:00 2001 From: PJBot Date: Sat, 14 Sep 2024 20:41:44 +0000 Subject: [PATCH 049/138] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 7276b3e3787..2215566c344 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: JIPDawg - changes: - - message: Added Late join CryoSleepers to Origin. - type: Tweak - id: 6875 - time: '2024-07-06T17:33:20.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29761 - author: Beck Thompson changes: - message: Splashing reagents on players will now apply the correct amounts. @@ -3919,3 +3912,10 @@ id: 7374 time: '2024-09-14T17:19:32.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/32070 +- author: lzk228 + changes: + - message: Command intercom now reinforced the same way as the security one. + type: Tweak + id: 7375 + time: '2024-09-14T20:40:38.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/32169 From 4da704fd9c15df803980cedbca992048abc51343 Mon Sep 17 00:00:00 2001 From: deltanedas <39013340+deltanedas@users.noreply.github.com> Date: Sat, 14 Sep 2024 21:12:01 +0000 Subject: [PATCH 050/138] clean up clothing lathe recipes (#31520) * clean up clothing lathe recipes * add result * :trollface: --------- Co-authored-by: deltanedas <@deltanedas:kde.org> --- .../Prototypes/Recipes/Lathes/clothing.yml | 887 ++++++------------ 1 file changed, 294 insertions(+), 593 deletions(-) diff --git a/Resources/Prototypes/Recipes/Lathes/clothing.yml b/Resources/Prototypes/Recipes/Lathes/clothing.yml index 100cbe8f386..0db72f36636 100644 --- a/Resources/Prototypes/Recipes/Lathes/clothing.yml +++ b/Resources/Prototypes/Recipes/Lathes/clothing.yml @@ -1,1263 +1,964 @@ +# Base prototypes -# Jumpsuits/skirts - type: latheRecipe - id: ClothingUniformJumpsuitColorGrey # Tide - result: ClothingUniformJumpsuitColorGrey + abstract: true + id: BaseJumpsuitRecipe completetime: 4 materials: Cloth: 300 - type: latheRecipe - id: ClothingUniformJumpskirtColorGrey - result: ClothingUniformJumpskirtColorGrey - completetime: 4 + abstract: true + parent: BaseJumpsuitRecipe + id: BaseCommandJumpsuitRecipe materials: Cloth: 300 + Durathread: 100 + +- type: latheRecipe + abstract: true + id: BaseCoatRecipe + completetime: 3.2 # don't ask why its faster than a jumpsuit?? + materials: + Cloth: 500 + Durathread: 200 + +- type: latheRecipe + abstract: true + parent: BaseCoatRecipe + id: BaseCommandCoatRecipe + materials: + Cloth: 500 + Durathread: 300 + +- type: latheRecipe + abstract: true + id: BaseHatRecipe + completetime: 2 + materials: + Cloth: 100 - type: latheRecipe + abstract: true + id: BaseCarpetRecipe + completetime: 1 + materials: + Cloth: 100 + +- type: latheRecipe + abstract: true + parent: BaseHatRecipe + id: BaseCommandHatRecipe + materials: + Cloth: 100 + Durathread: 50 + +- type: latheRecipe + abstract: true + id: BaseNeckClothingRecipe + completetime: 2 + materials: + Cloth: 200 + +# Recipes + +# Jumpsuits/skirts +- type: latheRecipe + parent: BaseJumpsuitRecipe + id: ClothingUniformJumpsuitColorGrey # Tide + result: ClothingUniformJumpsuitColorGrey # Tide + +- type: latheRecipe + parent: BaseJumpsuitRecipe + id: ClothingUniformJumpskirtColorGrey + result: ClothingUniformJumpskirtColorGrey + +- type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpsuitBartender result: ClothingUniformJumpsuitBartender - completetime: 4 - materials: - Cloth: 300 - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpskirtBartender result: ClothingUniformJumpskirtBartender - completetime: 4 - materials: - Cloth: 300 - type: latheRecipe + parent: BaseCommandJumpsuitRecipe id: ClothingUniformJumpsuitCaptain result: ClothingUniformJumpsuitCaptain - completetime: 4 - materials: - Cloth: 300 - Durathread: 100 - type: latheRecipe + parent: BaseCommandJumpsuitRecipe id: ClothingUniformJumpsuitCapFormal result: ClothingUniformJumpsuitCapFormal - completetime: 4 - materials: - Cloth: 300 - Durathread: 100 - - type: latheRecipe + parent: BaseCommandJumpsuitRecipe id: ClothingUniformJumpskirtCapFormalDress result: ClothingUniformJumpskirtCapFormalDress - completetime: 4 - materials: - Cloth: 300 - Durathread: 100 - type: latheRecipe + parent: BaseCommandJumpsuitRecipe id: ClothingUniformJumpskirtCaptain result: ClothingUniformJumpskirtCaptain - completetime: 4 - materials: - Cloth: 300 - Durathread: 100 - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpsuitCargo result: ClothingUniformJumpsuitCargo - completetime: 4 - materials: - Cloth: 300 - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpskirtCargo result: ClothingUniformJumpskirtCargo - completetime: 4 - materials: - Cloth: 300 - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpsuitSalvageSpecialist result: ClothingUniformJumpsuitSalvageSpecialist - completetime: 4 - materials: - Cloth: 500 #It's armored but I don't want to include durathread for a non-head - type: latheRecipe + parent: BaseCommandJumpsuitRecipe id: ClothingUniformJumpsuitCentcomAgent result: ClothingUniformJumpsuitCentcomAgent - completetime: 4 - materials: - Cloth: 300 - Durathread: 100 - type: latheRecipe + parent: BaseCommandJumpsuitRecipe id: ClothingUniformJumpsuitCentcomFormal result: ClothingUniformJumpsuitCentcomFormal - completetime: 4 - materials: - Cloth: 300 - Durathread: 100 - type: latheRecipe + parent: BaseCommandJumpsuitRecipe id: ClothingUniformJumpskirtCentcomFormalDress result: ClothingUniformJumpskirtCentcomFormalDress - completetime: 4 - materials: - Cloth: 300 - Durathread: 100 - type: latheRecipe + parent: BaseCommandJumpsuitRecipe id: ClothingUniformJumpsuitCentcomOfficer result: ClothingUniformJumpsuitCentcomOfficer - completetime: 4 - materials: - Cloth: 300 - Durathread: 100 - type: latheRecipe + parent: BaseCommandJumpsuitRecipe id: ClothingUniformJumpsuitCentcomOfficial result: ClothingUniformJumpsuitCentcomOfficial - completetime: 4 - materials: - Cloth: 300 - Durathread: 100 + +## CE - type: latheRecipe + parent: BaseCommandJumpsuitRecipe id: ClothingUniformJumpsuitChiefEngineer result: ClothingUniformJumpsuitChiefEngineer - completetime: 4 - materials: - Cloth: 300 - Durathread: 100 - type: latheRecipe + parent: BaseCommandJumpsuitRecipe id: ClothingUniformJumpskirtChiefEngineer result: ClothingUniformJumpskirtChiefEngineer - completetime: 4 - materials: - Cloth: 300 - Durathread: 100 - type: latheRecipe + parent: BaseCommandJumpsuitRecipe id: ClothingUniformJumpsuitChiefEngineerTurtle result: ClothingUniformJumpsuitChiefEngineerTurtle - completetime: 4 - materials: - Cloth: 300 - type: latheRecipe + parent: BaseCommandJumpsuitRecipe id: ClothingUniformJumpskirtChiefEngineerTurtle result: ClothingUniformJumpskirtChiefEngineerTurtle - completetime: 4 - materials: - Cloth: 300 + +## Chaplain - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpsuitChaplain result: ClothingUniformJumpsuitChaplain - completetime: 4 - materials: - Cloth: 300 - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpskirtChaplain result: ClothingUniformJumpskirtChaplain - completetime: 4 - materials: - Cloth: 300 + +## Chef - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpsuitChef result: ClothingUniformJumpsuitChef - completetime: 4 - materials: - Cloth: 300 - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpskirtChef result: ClothingUniformJumpskirtChef - completetime: 4 - materials: - Cloth: 300 + +## Chemist - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpsuitChemistry result: ClothingUniformJumpsuitChemistry - completetime: 4 - materials: - Cloth: 300 - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpskirtChemistry result: ClothingUniformJumpskirtChemistry - completetime: 4 - materials: - Cloth: 300 + +## Clown - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpsuitClown result: ClothingUniformJumpsuitClown - completetime: 4 - materials: - Cloth: 300 + +## CMO - type: latheRecipe + parent: BaseCommandJumpsuitRecipe id: ClothingUniformJumpsuitCMO result: ClothingUniformJumpsuitCMO - completetime: 4 - materials: - Cloth: 300 - Durathread: 100 - type: latheRecipe + parent: BaseCommandJumpsuitRecipe id: ClothingUniformJumpskirtCMO result: ClothingUniformJumpskirtCMO - completetime: 4 - materials: - Cloth: 300 - Durathread: 100 - type: latheRecipe + parent: BaseCommandJumpsuitRecipe id: ClothingUniformJumpsuitCMOTurtle result: ClothingUniformJumpsuitCMOTurtle - completetime: 4 - materials: - Cloth: 300 - Durathread: 100 - type: latheRecipe + parent: BaseCommandJumpsuitRecipe id: ClothingUniformJumpskirtCMOTurtle result: ClothingUniformJumpskirtCMOTurtle - completetime: 4 - materials: - Cloth: 300 - Durathread: 100 + +## Detective - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpsuitDetective result: ClothingUniformJumpsuitDetective - completetime: 4 - materials: - Cloth: 300 - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpskirtDetective result: ClothingUniformJumpskirtDetective - completetime: 4 - materials: - Cloth: 300 + +## Engineer - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpsuitEngineering result: ClothingUniformJumpsuitEngineering - completetime: 4 - materials: - Cloth: 300 - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpskirtEngineering result: ClothingUniformJumpskirtEngineering - completetime: 4 - materials: - Cloth: 300 - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpsuitSeniorEngineer result: ClothingUniformJumpsuitSeniorEngineer - completetime: 4 - materials: - Cloth: 300 - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpskirtSeniorEngineer result: ClothingUniformJumpskirtSeniorEngineer - completetime: 4 - materials: - Cloth: 300 + +## HoP - type: latheRecipe + parent: BaseCommandJumpsuitRecipe id: ClothingUniformJumpsuitHoP result: ClothingUniformJumpsuitHoP - completetime: 4 - materials: - Cloth: 300 - Durathread: 100 - type: latheRecipe + parent: BaseCommandJumpsuitRecipe id: ClothingUniformJumpskirtHoP result: ClothingUniformJumpskirtHoP - completetime: 4 - materials: - Cloth: 300 - Durathread: 100 + +## HoS - type: latheRecipe + parent: BaseCommandJumpsuitRecipe id: ClothingUniformJumpsuitHoS result: ClothingUniformJumpsuitHoS - completetime: 4 - materials: - Cloth: 300 - Durathread: 100 - type: latheRecipe + parent: BaseCommandJumpsuitRecipe id: ClothingUniformJumpskirtHoS result: ClothingUniformJumpskirtHoS - completetime: 4 - materials: - Cloth: 300 - Durathread: 100 - type: latheRecipe + parent: BaseCommandJumpsuitRecipe id: ClothingUniformJumpsuitHosFormal result: ClothingUniformJumpsuitHosFormal - completetime: 4 - materials: - Cloth: 300 - Durathread: 100 - type: latheRecipe + parent: BaseCommandJumpsuitRecipe id: ClothingUniformJumpskirtHosFormal result: ClothingUniformJumpskirtHosFormal - completetime: 4 - materials: - Cloth: 300 - Durathread: 100 - type: latheRecipe + parent: BaseCommandJumpsuitRecipe id: ClothingUniformJumpsuitHoSParadeMale result: ClothingUniformJumpsuitHoSParadeMale - completetime: 5 - materials: - Cloth: 300 - Durathread: 100 - type: latheRecipe + parent: BaseCommandJumpsuitRecipe id: ClothingUniformJumpskirtHoSParadeMale result: ClothingUniformJumpskirtHoSParadeMale - completetime: 5 - materials: - Cloth: 300 - Durathread: 100 - type: latheRecipe + parent: BaseCommandJumpsuitRecipe id: ClothingUniformJumpsuitHoSAlt result: ClothingUniformJumpsuitHoSAlt - completetime: 4 - materials: - Cloth: 300 - Durathread: 100 - type: latheRecipe + parent: BaseCommandJumpsuitRecipe id: ClothingUniformJumpsuitHoSBlue result: ClothingUniformJumpsuitHoSBlue - completetime: 4 - materials: - Cloth: 300 - Durathread: 100 - type: latheRecipe + parent: BaseCommandJumpsuitRecipe id: ClothingUniformJumpsuitHoSGrey result: ClothingUniformJumpsuitHoSGrey - completetime: 4 - materials: - Cloth: 300 - Durathread: 100 - type: latheRecipe + parent: BaseCommandJumpsuitRecipe id: ClothingUniformJumpskirtHoSAlt result: ClothingUniformJumpskirtHoSAlt - completetime: 4 - materials: - Cloth: 300 - Durathread: 100 + +## Hydroponics - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpsuitHydroponics result: ClothingUniformJumpsuitHydroponics - completetime: 4 - materials: - Cloth: 300 - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpskirtHydroponics result: ClothingUniformJumpskirtHydroponics - completetime: 4 - materials: - Cloth: 300 + +## Janitor - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpsuitJanitor result: ClothingUniformJumpsuitJanitor - completetime: 4 - materials: - Cloth: 300 - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpskirtJanitor result: ClothingUniformJumpskirtJanitor - completetime: 4 - materials: - Cloth: 300 + +## Lawyer - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpsuitLawyerBlack result: ClothingUniformJumpsuitLawyerBlack - completetime: 4 - materials: - Cloth: 300 + +## Librarian - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpsuitLibrarian result: ClothingUniformJumpsuitLibrarian - completetime: 4 - materials: - Cloth: 300 - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpskirtColorLightBrown #Librarian - result: ClothingUniformJumpskirtColorLightBrown - completetime: 4 - materials: - Cloth: 300 + result: ClothingUniformJumpskirtColorLightBrown #Librarian + +## Medical Doctor - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpsuitMedicalDoctor result: ClothingUniformJumpsuitMedicalDoctor - completetime: 4 - materials: - Cloth: 300 - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpskirtMedicalDoctor result: ClothingUniformJumpskirtMedicalDoctor - completetime: 4 - materials: - Cloth: 300 - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpsuitSeniorPhysician result: ClothingUniformJumpsuitSeniorPhysician - completetime: 4 - materials: - Cloth: 300 - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpskirtSeniorPhysician result: ClothingUniformJumpskirtSeniorPhysician - completetime: 4 - materials: - Cloth: 300 + +## Mime - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpsuitMime result: ClothingUniformJumpsuitMime - completetime: 4 - materials: - Cloth: 300 - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpskirtMime result: ClothingUniformJumpskirtMime - completetime: 4 - materials: - Cloth: 300 + +## Musician - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpsuitMusician result: ClothingUniformJumpsuitMusician - completetime: 4 - materials: - Cloth: 300 + +## Operative - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpsuitOperative result: ClothingUniformJumpsuitOperative - completetime: 4 - materials: - Cloth: 300 - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpskirtOperative result: ClothingUniformJumpskirtOperative - completetime: 4 - materials: - Cloth: 300 + +## Paramedic - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpsuitParamedic result: ClothingUniformJumpsuitParamedic - completetime: 4 - materials: - Cloth: 300 - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpskirtParamedic result: ClothingUniformJumpskirtParamedic - completetime: 4 - materials: - Cloth: 300 + +## Senior Officer - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpsuitSeniorOfficer result: ClothingUniformJumpsuitSeniorOfficer - completetime: 4 - materials: - Cloth: 300 - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpskirtSeniorOfficer result: ClothingUniformJumpskirtSeniorOfficer - completetime: 4 - materials: - Cloth: 300 + +## Prisoner - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpsuitPrisoner result: ClothingUniformJumpsuitPrisoner - completetime: 4 - materials: - Cloth: 300 - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpskirtPrisoner result: ClothingUniformJumpskirtPrisoner - completetime: 4 - materials: - Cloth: 300 + +## QM - type: latheRecipe + parent: BaseCommandJumpsuitRecipe id: ClothingUniformJumpsuitQM result: ClothingUniformJumpsuitQM - completetime: 4 - materials: - Cloth: 300 - Durathread: 100 - type: latheRecipe + parent: BaseCommandJumpsuitRecipe id: ClothingUniformJumpsuitQMFormal result: ClothingUniformJumpsuitQMFormal - completetime: 4 - materials: - Cloth: 300 - Durathread: 100 - type: latheRecipe + parent: BaseCommandJumpsuitRecipe id: ClothingUniformJumpskirtQM result: ClothingUniformJumpskirtQM - completetime: 4 - materials: - Cloth: 300 - Durathread: 100 - type: latheRecipe + parent: BaseCommandJumpsuitRecipe id: ClothingUniformJumpsuitQMTurtleneck result: ClothingUniformJumpsuitQMTurtleneck - completetime: 4 - materials: - Cloth: 300 - Durathread: 100 - type: latheRecipe + parent: BaseCommandJumpsuitRecipe id: ClothingUniformJumpskirtQMTurtleneck result: ClothingUniformJumpskirtQMTurtleneck - completetime: 4 - materials: - Cloth: 300 - Durathread: 100 + +## RD - type: latheRecipe + parent: BaseCommandJumpsuitRecipe id: ClothingUniformJumpsuitResearchDirector result: ClothingUniformJumpsuitResearchDirector - completetime: 4 - materials: - Cloth: 300 - Durathread: 100 - type: latheRecipe + parent: BaseCommandJumpsuitRecipe id: ClothingUniformJumpskirtResearchDirector result: ClothingUniformJumpskirtResearchDirector - completetime: 4 - materials: - Cloth: 300 - Durathread: 100 + +## Scientist - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpsuitScientist result: ClothingUniformJumpsuitScientist - completetime: 4 - materials: - Cloth: 300 - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpskirtScientist result: ClothingUniformJumpskirtScientist - completetime: 4 - materials: - Cloth: 300 - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpsuitSeniorResearcher result: ClothingUniformJumpsuitSeniorResearcher - completetime: 4 - materials: - Cloth: 300 - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpskirtSeniorResearcher result: ClothingUniformJumpskirtSeniorResearcher - completetime: 4 - materials: - Cloth: 300 + +## Security Officer - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpsuitSec result: ClothingUniformJumpsuitSec - completetime: 4 - materials: - Cloth: 300 - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpskirtSec result: ClothingUniformJumpskirtSec - completetime: 4 - materials: - Cloth: 300 + +## Brigmedic - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpsuitBrigmedic result: ClothingUniformJumpsuitBrigmedic - completetime: 4 - materials: - Cloth: 300 - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpskirtBrigmedic result: ClothingUniformJumpskirtBrigmedic - completetime: 4 - materials: - Cloth: 300 - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpsuitSyndieFormal result: ClothingUniformJumpsuitSyndieFormal - completetime: 4 - materials: - Cloth: 300 - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpskirtSyndieFormalDress result: ClothingUniformJumpskirtSyndieFormalDress - completetime: 4 - materials: - Cloth: 300 - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpsuitPyjamaSyndicateBlack result: ClothingUniformJumpsuitPyjamaSyndicateBlack - completetime: 4 - materials: - Cloth: 300 - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpsuitPyjamaSyndicatePink result: ClothingUniformJumpsuitPyjamaSyndicatePink - completetime: 4 - materials: - Cloth: 300 - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpsuitPyjamaSyndicateRed result: ClothingUniformJumpsuitPyjamaSyndicateRed - completetime: 4 - materials: - Cloth: 300 - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpsuitWarden result: ClothingUniformJumpsuitWarden - completetime: 4 - materials: - Cloth: 300 - type: latheRecipe + parent: BaseJumpsuitRecipe id: ClothingUniformJumpskirtWarden result: ClothingUniformJumpskirtWarden - completetime: 4 - materials: - Cloth: 300 # Command winter coats - type: latheRecipe + parent: BaseCommandCoatRecipe id: ClothingOuterWinterCap result: ClothingOuterWinterCap - completetime: 3.2 - materials: - Cloth: 500 - Durathread: 300 - type: latheRecipe + parent: BaseCommandCoatRecipe id: ClothingOuterWinterCE result: ClothingOuterWinterCE - completetime: 3.2 - materials: - Cloth: 500 - Durathread: 300 - type: latheRecipe + parent: BaseCommandCoatRecipe id: ClothingOuterWinterCentcom result: ClothingOuterWinterCentcom - completetime: 3.2 - materials: - Cloth: 500 - Durathread: 300 - type: latheRecipe + parent: BaseCommandCoatRecipe id: ClothingOuterWinterCMO result: ClothingOuterWinterCMO - completetime: 3.2 - materials: - Cloth: 500 - Durathread: 300 - type: latheRecipe + parent: BaseCommandCoatRecipe id: ClothingOuterWinterHoP result: ClothingOuterWinterHoP - completetime: 3.2 - materials: - Cloth: 500 - Durathread: 300 - type: latheRecipe + parent: BaseCommandCoatRecipe id: ClothingOuterWinterHoSUnarmored result: ClothingOuterWinterHoSUnarmored - completetime: 3.2 - materials: - Cloth: 500 - Durathread: 300 - type: latheRecipe + parent: BaseCommandCoatRecipe id: ClothingOuterWinterWardenUnarmored result: ClothingOuterWinterWardenUnarmored - completetime: 3.2 - materials: - Cloth: 500 - Durathread: 300 - type: latheRecipe + parent: BaseCommandCoatRecipe id: ClothingOuterWinterQM result: ClothingOuterWinterQM - completetime: 3.2 - materials: - Cloth: 500 - Durathread: 300 - type: latheRecipe + parent: BaseCommandCoatRecipe id: ClothingOuterWinterRD result: ClothingOuterWinterRD - completetime: 3.2 - materials: - Cloth: 500 - Durathread: 300 # Winter coats - type: latheRecipe + parent: BaseCoatRecipe id: ClothingOuterWinterMusician result: ClothingOuterWinterMusician - completetime: 3.2 - materials: - Cloth: 500 - Durathread: 200 - type: latheRecipe + parent: BaseCoatRecipe id: ClothingOuterWinterClown result: ClothingOuterWinterClown - completetime: 3.2 - materials: - Cloth: 500 - Durathread: 200 - type: latheRecipe + parent: BaseCoatRecipe id: ClothingOuterWinterMime result: ClothingOuterWinterMime - completetime: 3.2 - materials: - Cloth: 500 - Durathread: 200 - type: latheRecipe + parent: BaseCoatRecipe id: ClothingOuterWinterCoat result: ClothingOuterWinterCoat - completetime: 3.2 - materials: - Cloth: 500 - Durathread: 200 - type: latheRecipe + parent: BaseCoatRecipe id: ClothingOuterWinterJani result: ClothingOuterWinterJani - completetime: 3.2 - materials: - Cloth: 500 - Durathread: 200 - type: latheRecipe + parent: BaseCoatRecipe id: ClothingOuterWinterBar result: ClothingOuterWinterBar - completetime: 3.2 - materials: - Cloth: 500 - Durathread: 200 - type: latheRecipe + parent: BaseCoatRecipe id: ClothingOuterWinterChef result: ClothingOuterWinterChef - completetime: 3.2 - materials: - Cloth: 500 - Durathread: 200 - type: latheRecipe + parent: BaseCoatRecipe id: ClothingOuterWinterHydro result: ClothingOuterWinterHydro - completetime: 3.2 - materials: - Cloth: 500 - Durathread: 200 - type: latheRecipe + parent: BaseCoatRecipe id: ClothingOuterWinterAtmos result: ClothingOuterWinterAtmos - completetime: 3.2 - materials: - Cloth: 500 - Durathread: 200 - type: latheRecipe + parent: BaseCoatRecipe id: ClothingOuterWinterEngi result: ClothingOuterWinterEngi - completetime: 3.2 - materials: - Cloth: 500 - Durathread: 200 - type: latheRecipe + parent: BaseCoatRecipe id: ClothingOuterWinterCargo result: ClothingOuterWinterCargo - completetime: 3.2 - materials: - Cloth: 500 - Durathread: 200 - type: latheRecipe + parent: BaseCoatRecipe id: ClothingOuterWinterMiner result: ClothingOuterWinterMiner - completetime: 3.2 - materials: - Cloth: 500 - Durathread: 200 - type: latheRecipe + parent: BaseCoatRecipe id: ClothingOuterWinterMed result: ClothingOuterWinterMed - completetime: 3.2 - materials: - Cloth: 500 - Durathread: 200 - type: latheRecipe + parent: BaseCoatRecipe id: ClothingOuterWinterPara result: ClothingOuterWinterPara - completetime: 3.2 - materials: - Cloth: 500 - Durathread: 200 - type: latheRecipe + parent: BaseCoatRecipe id: ClothingOuterWinterChem result: ClothingOuterWinterChem - completetime: 3.2 - materials: - Cloth: 500 - Durathread: 200 - type: latheRecipe + parent: BaseCoatRecipe id: ClothingOuterWinterGen result: ClothingOuterWinterGen - completetime: 3.2 - materials: - Cloth: 500 - Durathread: 200 - type: latheRecipe + parent: BaseCoatRecipe id: ClothingOuterWinterViro result: ClothingOuterWinterViro - completetime: 3.2 - materials: - Cloth: 500 - Durathread: 200 - type: latheRecipe + parent: BaseCoatRecipe id: ClothingOuterWinterSci result: ClothingOuterWinterSci - completetime: 3.2 - materials: - Cloth: 500 - Durathread: 200 - type: latheRecipe + parent: BaseCoatRecipe id: ClothingOuterWinterRobo result: ClothingOuterWinterRobo - completetime: 3.2 - materials: - Cloth: 500 - Durathread: 200 - type: latheRecipe + parent: BaseCoatRecipe id: ClothingOuterWinterSec result: ClothingOuterWinterSec - completetime: 3.2 - materials: - Cloth: 500 - Durathread: 200 - type: latheRecipe + parent: BaseCoatRecipe id: ClothingOuterWinterSyndie result: ClothingOuterWinterSyndie - completetime: 3.2 - materials: - Cloth: 500 - Durathread: 200 - type: latheRecipe + parent: BaseCoatRecipe id: ClothingOuterWinterSyndieCap result: ClothingOuterWinterSyndieCap - completetime: 3.2 - materials: - Cloth: 500 - Durathread: 200 # Hats - type: latheRecipe + parent: BaseCommandHatRecipe id: ClothingHeadHatCaptain result: ClothingHeadHatCaptain - completetime: 2 - materials: - Cloth: 100 - Durathread: 50 - type: latheRecipe + parent: BaseCommandHatRecipe id: ClothingHeadHatCapcap result: ClothingHeadHatCapcap - completetime: 2 - materials: - Cloth: 100 - Durathread: 50 - type: latheRecipe + parent: BaseCommandHatRecipe + id: ClothingHeadHatCentcom + result: ClothingHeadHatCentcom + +- type: latheRecipe + parent: BaseCommandHatRecipe + id: ClothingHeadHatCentcomcap + result: ClothingHeadHatCentcomcap + +- type: latheRecipe + parent: BaseCommandHatRecipe id: ClothingHeadHatBeretHoS result: ClothingHeadHatBeretHoS - completetime: 2 - materials: - Cloth: 100 - Durathread: 50 - type: latheRecipe + parent: BaseCommandHatRecipe id: ClothingHeadHatHoshat result: ClothingHeadHatHoshat - completetime: 2 - materials: - Cloth: 100 - Durathread: 50 - type: latheRecipe + parent: BaseCommandHatRecipe id: ClothingHeadHatWarden result: ClothingHeadHatWarden - completetime: 2 - materials: - Cloth: 100 - Durathread: 50 - type: latheRecipe + parent: BaseCommandHatRecipe id: ClothingHeadHatBeretWarden result: ClothingHeadHatBeretWarden - completetime: 2 - materials: - Cloth: 100 - Durathread: 50 - type: latheRecipe + parent: BaseCommandHatRecipe id: ClothingHeadHatHopcap result: ClothingHeadHatHopcap - completetime: 2 - materials: - Cloth: 100 - Durathread: 50 - type: latheRecipe + parent: BaseCommandHatRecipe id: ClothingHeadHatQMsoft result: ClothingHeadHatQMsoft - completetime: 2 - materials: - Cloth: 100 - Durathread: 50 - type: latheRecipe + parent: BaseCommandHatRecipe id: ClothingHeadHatBeretRND result: ClothingHeadHatBeretRND - completetime: 2 - materials: - Cloth: 100 - Durathread: 50 - type: latheRecipe + parent: BaseCommandHatRecipe id: ClothingHeadHatBeretEngineering result: ClothingHeadHatBeretEngineering - completetime: 2 - materials: - Cloth: 100 - Durathread: 50 - type: latheRecipe + parent: BaseCommandHatRecipe id: ClothingHeadHatBeretQM result: ClothingHeadHatBeretQM - completetime: 2 - materials: - Cloth: 100 - Durathread: 50 - type: latheRecipe + parent: BaseCommandHatRecipe id: ClothingHeadHatBeretCmo result: ClothingHeadHatBeretCmo - completetime: 2 - materials: - Cloth: 100 - Durathread: 50 + +# Non-command hats - type: latheRecipe + parent: BaseHatRecipe id: ClothingHeadHatBeretMedic result: ClothingHeadHatBeretMedic - completetime: 2 - materials: - Cloth: 100 - type: latheRecipe + parent: BaseHatRecipe id: ClothingHeadHatBeretBrigmedic result: ClothingHeadHatBeretBrigmedic - completetime: 2 - materials: - Cloth: 100 - type: latheRecipe + parent: BaseHatRecipe id: ClothingHeadHatBeretSecurity result: ClothingHeadHatBeretSecurity - completetime: 2 - materials: - Cloth: 100 - type: latheRecipe + parent: BaseHatRecipe id: ClothingHeadHatBeretSeniorPhysician result: ClothingHeadHatBeretSeniorPhysician - completetime: 2 - materials: - Cloth: 100 - -- type: latheRecipe - id: ClothingHeadHatCentcom - result: ClothingHeadHatCentcom - completetime: 2 - materials: - Cloth: 100 - Durathread: 50 - -- type: latheRecipe - id: ClothingHeadHatCentcomcap - result: ClothingHeadHatCentcomcap - completetime: 2 - materials: - Cloth: 100 - Durathread: 50 - type: latheRecipe + parent: BaseHatRecipe id: ClothingHeadHatSyndie result: ClothingHeadHatSyndie - completetime: 2 - materials: - Cloth: 100 - type: latheRecipe + parent: BaseHatRecipe id: ClothingHeadHatSyndieMAA result: ClothingHeadHatSyndieMAA - completetime: 2 - materials: - Cloth: 100 - type: latheRecipe + parent: BaseHatRecipe id: ClothingHeadPyjamaSyndicateBlack result: ClothingHeadPyjamaSyndicateBlack - completetime: 2 - materials: - Cloth: 100 - type: latheRecipe + parent: BaseHatRecipe id: ClothingHeadPyjamaSyndicatePink result: ClothingHeadPyjamaSyndicatePink - completetime: 2 - materials: - Cloth: 100 - type: latheRecipe + parent: BaseHatRecipe id: ClothingHeadPyjamaSyndicateRed result: ClothingHeadPyjamaSyndicateRed - completetime: 2 - materials: - Cloth: 100 - type: latheRecipe + parent: BaseHatRecipe id: ClothingHeadHatParamedicsoft result: ClothingHeadHatParamedicsoft - completetime: 1 - materials: - Cloth: 100 # Ties - type: latheRecipe + parent: BaseNeckClothingRecipe id: ClothingNeckTieRed result: ClothingNeckTieRed - completetime: 2 - materials: - Cloth: 200 - type: latheRecipe + parent: BaseNeckClothingRecipe id: ClothingNeckTieDet result: ClothingNeckTieDet - completetime: 2 - materials: - Cloth: 200 - type: latheRecipe + parent: BaseNeckClothingRecipe id: ClothingNeckTieSci result: ClothingNeckTieSci - completetime: 2 - materials: - Cloth: 200 # Scarfs - type: latheRecipe + parent: BaseNeckClothingRecipe id: ClothingNeckScarfStripedGreen result: ClothingNeckScarfStripedGreen - completetime: 2 - materials: - Cloth: 200 - type: latheRecipe + parent: BaseNeckClothingRecipe id: ClothingNeckScarfStripedBlue result: ClothingNeckScarfStripedBlue - completetime: 2 - materials: - Cloth: 200 - type: latheRecipe + parent: BaseNeckClothingRecipe id: ClothingNeckScarfStripedRed result: ClothingNeckScarfStripedRed - completetime: 2 - materials: - Cloth: 200 - type: latheRecipe + parent: BaseNeckClothingRecipe id: ClothingNeckScarfStripedBrown result: ClothingNeckScarfStripedBrown - completetime: 2 - materials: - Cloth: 200 - type: latheRecipe + parent: BaseNeckClothingRecipe id: ClothingNeckScarfStripedLightBlue result: ClothingNeckScarfStripedLightBlue - completetime: 2 - materials: - Cloth: 200 - type: latheRecipe + parent: BaseNeckClothingRecipe id: ClothingNeckScarfStripedOrange result: ClothingNeckScarfStripedOrange - completetime: 2 - materials: - Cloth: 200 - type: latheRecipe + parent: BaseNeckClothingRecipe id: ClothingNeckScarfStripedBlack result: ClothingNeckScarfStripedBlack - completetime: 2 - materials: - Cloth: 200 - type: latheRecipe + parent: BaseNeckClothingRecipe id: ClothingNeckScarfStripedPurple result: ClothingNeckScarfStripedPurple - completetime: 2 - materials: - Cloth: 200 # Carpets - type: latheRecipe + parent: BaseCarpetRecipe id: Carpet result: FloorCarpetItemRed - completetime: 1 - materials: - Cloth: 100 - type: latheRecipe + parent: BaseCarpetRecipe id: CarpetBlack result: FloorCarpetItemBlack - completetime: 1 - materials: - Cloth: 100 - type: latheRecipe + parent: BaseCarpetRecipe id: CarpetPink result: FloorCarpetItemPink - completetime: 1 - materials: - Cloth: 100 - type: latheRecipe + parent: BaseCarpetRecipe id: CarpetBlue result: FloorCarpetItemBlue - completetime: 1 - materials: - Cloth: 100 - type: latheRecipe + parent: BaseCarpetRecipe id: CarpetGreen result: FloorCarpetItemGreen - completetime: 1 - materials: - Cloth: 100 - type: latheRecipe + parent: BaseCarpetRecipe id: CarpetOrange result: FloorCarpetItemOrange - completetime: 1 - materials: - Cloth: 100 - type: latheRecipe + parent: BaseCarpetRecipe id: CarpetPurple result: FloorCarpetItemPurple - completetime: 1 - materials: - Cloth: 100 - type: latheRecipe + parent: BaseCarpetRecipe id: CarpetCyan result: FloorCarpetItemCyan - completetime: 1 - materials: - Cloth: 100 - type: latheRecipe + parent: BaseCarpetRecipe id: CarpetWhite result: FloorCarpetItemWhite - completetime: 1 - materials: - Cloth: 100 From b33aa1aaee6ca5c1bd02c0e7cfd270571cc43b6a Mon Sep 17 00:00:00 2001 From: Winkarst <74284083+Winkarst-cpu@users.noreply.github.com> Date: Sun, 15 Sep 2024 00:34:44 +0300 Subject: [PATCH 051/138] Use Transform instead of TryComp (#32170) Use Transform instead of TryComp --- Content.Server/Gravity/GravityGeneratorSystem.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Content.Server/Gravity/GravityGeneratorSystem.cs b/Content.Server/Gravity/GravityGeneratorSystem.cs index 5ab2dc89310..9d58b82d690 100644 --- a/Content.Server/Gravity/GravityGeneratorSystem.cs +++ b/Content.Server/Gravity/GravityGeneratorSystem.cs @@ -36,8 +36,10 @@ public override void Update(float frameTime) private void OnActivated(Entity ent, ref ChargedMachineActivatedEvent args) { ent.Comp.GravityActive = true; - if (TryComp(ent, out var xform) && - TryComp(xform.ParentUid, out GravityComponent? gravity)) + + var xform = Transform(ent); + + if (TryComp(xform.ParentUid, out GravityComponent? gravity)) { _gravitySystem.EnableGravity(xform.ParentUid, gravity); } @@ -46,8 +48,10 @@ private void OnActivated(Entity ent, ref ChargedMachi private void OnDeactivated(Entity ent, ref ChargedMachineDeactivatedEvent args) { ent.Comp.GravityActive = false; - if (TryComp(ent, out var xform) && - TryComp(xform.ParentUid, out GravityComponent? gravity)) + + var xform = Transform(ent); + + if (TryComp(xform.ParentUid, out GravityComponent? gravity)) { _gravitySystem.RefreshGravity(xform.ParentUid, gravity); } From 940e791b13b238ecff67a17afce61fd276925b76 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 15 Sep 2024 11:51:05 +1000 Subject: [PATCH 052/138] Update Credits (#32178) Co-authored-by: PJBot --- Resources/Credits/GitHub.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Credits/GitHub.txt b/Resources/Credits/GitHub.txt index c6ec284dc84..1190feea712 100644 --- a/Resources/Credits/GitHub.txt +++ b/Resources/Credits/GitHub.txt @@ -1 +1 @@ -0x6273, 2013HORSEMEATSCANDAL, 20kdc, 21Melkuu, 4dplanner, 612git, 778b, Ablankmann, Acruid, actioninja, adamsong, Admiral-Obvious-001, Adrian16199, Aerocrux, Aeshus, Aexxie, Afrokada, Agoichi, AJCM-git, AjexRose, Alekshhh, AlexMorgan3817, AlmondFlour, Altoids1, amylizzle, ancientpower, ArchPigeon, Arendian, arimah, ArkiveDev, Arteben, AruMoon, as334, asperger-sind, aspiringLich, avghdev, AzzyIsNotHere, BananaFlambe, BasedUser, beck-thompson, BGare, bhenrich, Bixkitts, Blackern5000, Blazeror, blueDev2, Boaz1111, BobdaBiscuit, BombasterDS, brainfood1183, Brandon-Huu, Bright0, brndd, c4llv07e, CaasGit, CaptainSqrBeard, Carbonhell, CatTheSystem, Centronias, chairbender, Charlese2, chavonadelal, Cheackraze, cheesePizza2, Chief-Engineer, chromiumboy, Chronophylos, Ciac32, Clyybber, Cojoke-dot, ColdAutumnRain, collinlunn, ComicIronic, coolmankid12345, corentt, crazybrain23, creadth, CrigCrag, Crotalus, CrudeWax, Cyberboss, d34d10cc, Daemon, daerSeebaer, dahnte, dakamakat, dakimasu, DamianX, DangerRevolution, daniel-cr, Darkenson, DawBla, dch-GH, Deahaka, DEATHB4DEFEAT, DeathCamel58, deathride58, DebugOk, Decappi, Deeeeja, deepdarkdepths, Delete69, deltanedas, DerbyX, dffdff2423, DieselMohawk, Doctor-Cpu, DoctorBeard, DogZeroX, dontbetank, Doomsdrayk, Doru991, DoubleRiceEddiedd, DoutorWhite, DrMelon, DrSmugleaf, drteaspoon420, DTanxxx, DubiousDoggo, Duddino, Dutch-VanDerLinde, Easypoller, eclips_e, EdenTheLiznerd, EEASAS, Efruit, ElectroSR, elthundercloud, Emisse, EmoGarbage404, Endecc, enumerate0, eoineoineoin, ERORR404V1, Errant-4, estacaoespacialpirata, exincore, exp111, Fahasor, FairlySadPanda, ficcialfaint, Fildrance, FillerVK, Fishfish458, Flareguy, FluffiestFloof, FoLoKe, fooberticus, Fortune117, freeman2651, Fromoriss, FungiFellow, Futuristic-OK, GalacticChimp, gbasood, Geekyhobo, Genkail, geraeumig, Ghagliiarghii, Git-Nivrak, github-actions[bot], gituhabu, GNF54, godisdeadLOL, Golinth, GoodWheatley, graevy, GreyMario, gusxyz, Gyrandola, h3half, Hanzdegloker, Hardly3D, harikattar, HerCoyote23, hitomishirichan, Hmeister-real, HoofedEar, Hoolny, hord-brayden, hubismal, Hugal31, Huxellberger, iacore, IamVelcroboy, Ian321, icekot8, IgorAnt028, igorsaux, ike709, Illiux, Ilya246, IlyaElDunaev, Injazz, Insineer, Interrobang01, IProduceWidgets, ItsMeThom, Jackal298, Jackrost, jamessimo, janekvap, JerryImMouse, Jessetriesagain, jessicamaybe, Jezithyr, jicksaw, JiimBob, JIPDawg, JoeHammad1844, joelsgp, JohnGinnane, johnku1, joshepvodka, jproads, Jrpl, juliangiebel, JustArt1m, JustCone14, JustinTrotter, K-Dynamic, KaiShibaa, kalane15, kalanosh, Keer-Sar, Kelrak, kerisargit, keronshb, KIBORG04, Killerqu00, KingFroozy, kira-er, Kit0vras, KittenColony, Ko4ergaPunk, komunre, koteq, Krunklehorn, Kukutis96513, kxvvv, Lamrr, LankLTE, laok233, lapatison, LetterN, Level10Cybermancer, lever1209, liltenhead, LittleBuilderJane, Lomcastar, LordCarve, LordEclipse, luckyshotpictures, Lukasz825700516, lunarcomets, luringens, lvvova1, lzimann, lzk228, MACMAN2003, Macoron, Magicalus, MagnusCrowe, ManelNavola, Mangohydra, marboww, Matz05, MehimoNemo, MeltedPixel, MemeProof, Menshin, MerrytheManokit, Mervill, metalgearsloth, mhamsterr, MilenVolf, Minty642, Mirino97, mirrorcult, misandrie, MishaUnity, MisterMecky, Mith-randalf, MjrLandWhale, Moneyl, Moomoobeef, moony, Morb0, Mr0maks, MureixloI, musicmanvr, Myakot, Myctai, N3X15, Nairodian, Naive817, NakataRin, namespace-Memory, NickPowers43, nikthechampiongr, Nimfar11, Nirnael, nmajask, nok-ko, Nopey, notafet, notquitehadouken, noudoit, nuke-haus, NULL882, nyeogmi, OctoRocket, OldDanceJacket, onoira, osjarw, Owai-Seek, pali6, Pangogie, patrikturi, PaulRitter, Peptide90, peptron1, Phantom-Lily, pigeonpeas, pissdemon, PixelTheKermit, PJB3005, Plykiya, pofitlo, pointer-to-null, PolterTzi, PoorMansDreams, PopGamer45, potato1234x, ProfanedBane, PrPleGoo, ps3moira, Psychpsyo, psykzz, PuroSlavKing, PursuitInAshes, quatre, QuietlyWhisper, qwerltaz, Radosvik, Radrark, Rainbeon, Rainfey, RamZ, Rane, ravage123321, rbertoche, Redict, RedlineTriad, redmushie, RednoWCirabrab, RemberBM, RemieRichards, RemTim, rene-descartes2021, RiceMar1244, RieBi, Rinkashikachi, Rockdtben, rolfero, rosieposieeee, RumiTiger, Saakra, saintmuntzer, SaphireLattice, Sarahon, ScalyChimp, ScarKy0, scrato, Scribbles0, Serkket, ShadowCommander, Shadowtheprotogen546, shampunj, SignalWalker, Simyon264, Sirionaut, Skarletto, Skrauz, Skyedra, SlamBamActionman, slarticodefast, Slava0135, snebl, Snowni, snowsignal, SonicHDC, SoulFN, SoulSloth, SpaceManiac, SpeltIncorrectyl, Spessmann, SphiraI, spoogemonster, ssdaniel24, stalengd, Stealthbomber16, StrawberryMoses, superjj18, SweptWasTaken, Szunti, takemysoult, TaralGit, Tayrtahn, tday93, TekuNut, TemporalOroboros, tentekal, Terraspark4941, tgrkzus, thatrandomcanadianguy, TheArturZh, theashtronaut, thedraccx, themias, Theomund, theOperand, TheShuEd, thetolbean, TimrodDX, Titian3, tkdrg, tmtmtl30, TokenStyle, tom-leys, tomasalves8, Tomeno, Tornado-Technology, tosatur, TsjipTsjip, Tunguso4ka, TurboTrackerss14, TyAshley, Tyler-IN, Tyzemol, UbaserB, UBlueberry, UKNOWH, Unkn0wnGh0st333, Uriende, UristMcDorf, Vaaankas, Varen, VasilisThePikachu, veliebm, Veritius, Vermidia, Verslebas, VigersRay, Visne, volundr-, Voomra, Vordenburg, vulppine, wafehling, WarMechanic, waylon531, weaversam8, whateverusername0, Willhelm53, Winkarst-cpu, wixoaGit, WlarusFromDaSpace, wrexbe, xRiriq, yathxyz, Ygg01, YotaXP, YuriyKiss, zach-hill, Zandario, Zap527, Zealith-Gamer, ZelteHonor, zerorulez, zionnBE, ZNixian, ZoldorfTheWizard, Zonespace27, Zumorica, Zymem +0x6273, 12rabbits, 13spacemen, 2013HORSEMEATSCANDAL, 20kdc, 21Melkuu, 3nderall, 4310v343k, 4dplanner, 612git, 778b, Ablankmann, abregado, Absolute-Potato, achookh, Acruid, actioninja, actually-reb, ada-please, adamsong, Adeinitas, Admiral-Obvious-001, adrian, Adrian16199, Ady4ik, Aerocrux, Aeshus, Aexolott, Aexxie, africalimedrop, Afrokada, Agoichi, Ahion, aiden, AJCM-git, AjexRose, Alekshhh, alexkar598, AlexMorgan3817, alexumandxgabriel08x, Alithsko, ALMv1, Alpha-Two, AlphaQwerty, Altoids1, amylizzle, ancientpower, Andre19926, AndrewEyeke, AndreyCamper, Anzarot121, Appiah, ar4ill, ArchPigeon, areitpog, Arendian, arimah, Arkanic, ArkiveDev, armoks, Arteben, ArthurMousatov, ArtisticRoomba, artur, AruMoon, ArZarLordOfMango, as334, AsikKEsel, asperger-sind, aspiringLich, astriloqua, AutoOtter, avghdev, Awlod, AzzyIsNotHere, backetako, BananaFlambe, Baptr0b0t, BasedUser, beck-thompson, bellwetherlogic, benev0, benjamin-burges, BGare, bhenrich, bhespiritu, bibbly, BIGZi0348, bingojohnson, BismarckShuffle, Bixkitts, Blackern5000, Blazeror, BlitzTheSquishy, bloodrizer, Bloody2372, blueDev2, Boaz1111, BobdaBiscuit, BobTheSleder, boiled-water-tsar, BombasterDS, botanySupremist, brainfood1183, BramvanZijp, Brandon-Huu, BriBrooo, Bright0, brndd, bryce0110, BubblegumBlue, buletsponge, buntobaggins, bvelliquette, byondfuckery, c0rigin, c4llv07e, CaasGit, Caconym27, Callmore, capnsockless, CaptainSqrBeard, Carbonhell, Carolyn3114, Carou02, carteblanche4me, CatTheSystem, Centronias, chairbender, Charlese2, ChaseFlorom, chavonadelal, Cheackraze, cheesePizza2, cheeseplated, Chief-Engineer, chillyconmor, christhirtle, chromiumboy, Chronophylos, Chubbicous, Chubbygummibear, Ciac32, civilCornball, Clement-O, clyf, Clyybber, CMDR-Piboy314, Cohnway, Cojoke-dot, ColdAutumnRain, Colin-Tel, collinlunn, ComicIronic, CookieMasterT, coolboy911, coolmankid12345, Coolsurf6, corentt, CormosLemming, crazybrain23, creadth, CrigCrag, croilbird, Crotalus, CrudeWax, CrzyPotato, Cyberboss, d34d10cc, DadeKuma, Daemon, daerSeebaer, dahnte, dakamakat, dakimasu, DakotaGay, DamianX, DangerRevolution, daniel-cr, DanSAussieITS, Daracke, Darkenson, DawBla, Daxxi3, dch-GH, Deahaka, dean, DEATHB4DEFEAT, DeathCamel58, Deatherd, deathride58, DebugOk, Decappi, Decortex, Deeeeja, deepdarkdepths, degradka, Delete69, deltanedas, DenisShvalov, DerbyX, derek, dersheppard, Deserty0, Detintinto, DevilishMilk, dexlerxd, dffdff2423, DieselMohawk, digitalic, Dimastra, DinoWattz, DisposableCrewmember42, DjfjdfofdjfjD, doc-michael, docnite, Doctor-Cpu, DoctorBeard, DogZeroX, dolgovmi, dontbetank, Doomsdrayk, Doru991, DoubleRiceEddiedd, DoutorWhite, dragonryan06, drakewill-CRL, Drayff, dreamlyjack, DrEnzyme, dribblydrone, DrMelon, drongood12, DrSingh, DrSmugleaf, drteaspoon420, DTanxxx, DubiousDoggo, Duddino, dukevanity, duskyjay, Dutch-VanDerLinde, dvir001, Dynexust, Easypoller, echo, eclips_e, eden077, EdenTheLiznerd, EEASAS, Efruit, efzapa, Ekkosangen, ElectroSR, elsie, elthundercloud, Elysium206, Emisse, emmafornash, EmoGarbage404, Endecc, eoineoineoin, eris, erohrs2, ERORR404V1, Errant-4, esguard, estacaoespacialpirata, eugene, exincore, exp111, f0x-n3rd, FacePluslll, Fahasor, FairlySadPanda, FATFSAAM2, Feluk6174, ficcialfaint, Fiftyllama, Fildrance, FillerVK, FinnishPaladin, FirinMaLazors, Fishfish458, FL-OZ, Flareguy, flashgnash, FluffiestFloof, FluidRock, foboscheshir, FoLoKe, fooberticus, ForestNoises, forgotmyotheraccount, forkeyboards, forthbridge, Fortune117, Fouin, foxhorn, freeman2651, freeze2222, Froffy025, Fromoriss, froozigiusz, FrostMando, FungiFellow, FunTust, Futuristic-OK, GalacticChimp, Gaxeer, gbasood, Geekyhobo, genderGeometries, GeneralGaws, Genkail, geraeumig, Ghagliiarghii, Git-Nivrak, githubuser508, gituhabu, GlassEclipse, GNF54, godisdeadLOL, Goldminermac, Golinth, GoodWheatley, Gorox221, graevy, GraniteSidewalk, GreaseMonk, greenrock64, GreyMario, GTRsound, gusxyz, Gyrandola, h3half, hamurlik, Hanzdegloker, HappyRoach, Hardly3D, harikattar, he1acdvv, Hebi, Henry, HerCoyote23, hitomishirichan, hiucko, Hmeister-fake, Hmeister-real, Hobbitmax, hobnob, HoidC, Holinka4ever, holyssss, HoofedEar, Hoolny, hord-brayden, Hreno, hubismal, Hugal31, Huxellberger, Hyenh, i-justuser-i, iacore, IamVelcroboy, Ian321, icekot8, icesickleone, iczero, iglov, IgorAnt028, igorsaux, ike709, illersaver, Illiux, Ilushkins33, Ilya246, IlyaElDunaev, imrenq, imweax, indeano, Injazz, Insineer, IntegerTempest, Interrobang01, IProduceWidgets, ItsMeThom, Itzbenz, iztokbajcar, Jackal298, Jackrost, jacksonzck, Jackw2As, jacob, jamessimo, janekvap, Jark255, Jaskanbe, JasperJRoth, jerryimmouse, JerryImMouse, Jessetriesagain, jessicamaybe, Jezithyr, jicksaw, JiimBob, JimGamemaster, jimmy12or, JIPDawg, jjtParadox, JoeHammad1844, joelsgp, JohnGinnane, johnku1, joshepvodka, jproads, Jrpl, juliangiebel, JustArt1m, JustCone14, justdie12, justin, justintether, JustinTrotter, justtne, K-Dynamic, k3yw, Kadeo64, Kaga-404, KaiShibaa, kalane15, kalanosh, katzenminer, kbailey-git, Keelin, Keer-Sar, KEEYNy, keikiru, Kelrak, kerisargit, keronshb, KIBORG04, Killerqu00, Kimpes, KingFroozy, kira-er, Kirillcas, Kirus59, Kistras, Kit0vras, KittenColony, klaypexx, Kmc2000, Ko4ergaPunk, kognise, kokoc9n, komunre, KonstantinAngelov, koteq, KrasnoshchekovPavel, Krunklehorn, Kukutis96513, Kupie, kxvvv, kyupolaris, kzhanik, lajolico, Lamrr, LankLTE, laok233, lapatison, larryrussian, lawdog4817, Lazzi0706, leander-0, leonardo-dabepis, leonsfriedrich, LeoSantich, LetterN, lettern, Level10Cybermancer, LEVELcat, lever1209, lgruthes, LightVillet, liltenhead, LinkUyx, LittleBuilderJane, lizelive, localcc, lokachop, Lomcastar, LordCarve, LordEclipse, LucasTheDrgn, luckyshotpictures, LudwigVonChesterfield, luizwritescode, Lukasz825700516, luminight, lunarcomets, luringens, lvvova1, Lyndomen, lyroth001, lzimann, lzk228, M3739, mac6na6na, MACMAN2003, Macoron, Magicalus, magmodius, MagnusCrowe, malchanceux, MaloTV, ManelNavola, Mangohydra, marboww, Markek1, Matz05, max, MaxNox7, maylokana, MehimoNemo, MeltedPixel, MemeProof, MendaxxDev, Menshin, Mephisto72, MerrytheManokit, Mervill, metalgearsloth, MetalSage, MFMessage, mhamsterr, michaelcu, micheel665, MilenVolf, milon, Minty642, Mirino97, mirrorcult, misandrie, MishaUnity, MisterMecky, Mith-randalf, MjrLandWhale, mkanke-real, MLGTASTICa, moderatelyaware, modern-nm, mokiros, Moneyl, Moomoobeef, moony, Morb0, mr-bo-jangles, Mr0maks, MrFippik, mrrobdemo, MureixloI, musicmanvr, MWKane, Myakot, Myctai, N3X15, nails-n-tape, Nairodian, Naive817, NakataRin, namespace-Memory, Nannek, NazrinNya, neutrino-laser, NickPowers43, nikthechampiongr, Nimfar11, Nirnael, NIXC, NkoKirkto, nmajask, noctyrnal, nok-ko, NonchalantNoob, NoobyLegion, Nopey, not-gavnaed, notafet, notquitehadouken, NotSoDana, noudoit, noverd, NuclearWinter, nukashimika, nuke-haus, NULL882, nullarmo, nyeogmi, Nylux, Nyranu, och-och, OctoRocket, OldDanceJacket, OliverOtter, onoira, OnyxTheBrave, OrangeMoronage9622, osjarw, Ostaf, othymer, OttoMaticode, Owai-Seek, packmore, paigemaeforrest, pali6, Pangogie, panzer-iv1, partyaddict, patrikturi, PaulRitter, peccneck, Peptide90, peptron1, PeterFuto, PetMudstone, pewter-wiz, Pgriha, Phantom-Lily, Phill101, phunnyguy, pigeonpeas, PilgrimViis, Pill-U, Pireax, Pissachu, pissdemon, PixeltheAertistContrib, PixelTheKermit, PJB3005, Plasmaguy, plinyvic, Plykiya, poeMota, pofitlo, pointer-to-null, pok27, PolterTzi, PoorMansDreams, PopGamer45, portfiend, potato1234x, PotentiallyTom, ProfanedBane, ProPandaBear, PrPleGoo, ps3moira, Pspritechologist, Psychpsyo, psykzz, PuceTint, PuroSlavKing, PursuitInAshes, Putnam3145, quatre, QueerNB, QuietlyWhisper, qwerltaz, RadioMull, Radosvik, Radrark, Rainbeon, Rainfey, Raitononai, Ramlik, RamZ, randy10122, Rane, Ranger6012, Rapidgame7, ravage123321, rbertoche, Redfire1331, Redict, RedlineTriad, redmushie, RednoWCirabrab, RemberBM, RemieRichards, RemTim, rene-descartes2021, Renlou, retequizzle, RiceMar1244, rich-dunne, RieBi, riggleprime, RIKELOLDABOSS, rinary1, Rinkashikachi, riolume, RobbyTheFish, Rockdtben, Rohesie, rok-povsic, rolfero, RomanNovo, rosieposieeee, Roudenn, router, RumiTiger, S1rFl0, S1ss3l, Saakra, saga3152, saintmuntzer, Salex08, sam, samgithubaccount, SaphireLattice, SapphicOverload, Sarahon, SaveliyM360, sBasalto, ScalyChimp, ScarKy0, scrato, Scribbles0, scruq445, scuffedjays, ScumbagDog, Segonist, sephtasm, Serkket, sewerpig, sh18rw, ShadeAware, ShadowCommander, Shadowtheprotogen546, shaeone, shampunj, shariathotpatrol, SignalWalker, siigiil, Simyon264, sirdragooon, Sirionaut, Sk1tch, SkaldetSkaeg, Skarletto, Skrauz, Skyedra, SlamBamActionman, slarticodefast, Slava0135, Slyfox333, snebl, snicket, sniperchance, Snowni, snowsignal, SolidusSnek, SonicHDC, SoulFN, SoulSloth, Soundwavesghost, SpaceManiac, SpaceyLady, spartak, SpartanKadence, SpeltIncorrectyl, Spessmann, SphiraI, SplinterGP, spoogemonster, sporekto, ssdaniel24, stalengd, stanberytrask, Stanislav4ix, StanTheCarpenter, Stealthbomber16, stellar-novas, stopbreaking, stopka-html, StrawberryMoses, Stray-Pyramid, strO0pwafel, Strol20, StStevens, Subversionary, sunbear-dev, superjj18, Supernorn, SweptWasTaken, Sybil, SYNCHRONIC, Szunti, Tainakov, takemysoult, TaralGit, Taran, taurie, Tayrtahn, tday93, TekuNut, telyonok, TemporalOroboros, tentekal, terezi4real, Terraspark4941, texcruize, TGODiamond, TGRCdev, tgrkzus, ThatOneGoblin25, thatrandomcanadianguy, TheArturZh, theashtronaut, thecopbennet, TheCze, TheDarkElites, thedraccx, TheEmber, TheIntoxicatedCat, thekilk, themias, Theomund, theOperand, TherapyGoth, TheShuEd, thetolbean, thevinter, TheWaffleJesus, Thinbug0, ThunderBear2006, timothyteakettle, TimrodDX, timurjavid, tin-man-tim, Titian3, tk-a369, tkdrg, tmtmtl30, TokenStyle, Tollhouse, tom-leys, tomasalves8, Tomeno, Tonydatguy, topy, Tornado-Technology, tosatur, TotallyLemon, tropicalhibi, truepaintgit, Truoizys, Tryded, TsjipTsjip, Tunguso4ka, TurboTrackerss14, TyAshley, Tyler-IN, Tyzemol, UbaserB, ubis1, UBlueberry, UKNOWH, Unbelievable-Salmon, underscorex5, UnicornOnLSD, Unisol, Unkn0wnGh0st333, unusualcrow, Uriende, UristMcDorf, user424242420, Vaaankas, valentfingerov, Varen, VasilisThePikachu, veliebm, VelonacepsCalyxEggs, veprolet, veritable-calamity, Veritius, Vermidia, vero5123, Verslebas, VigersRay, violet754, Visne, VMSolidus, voidnull000, volotomite, volundr-, Voomra, Vordenburg, vorkathbruh, vulppine, wafehling, Warentan, WarMechanic, Watermelon914, waylon531, weaversam8, wertanchik, whateverusername0, Willhelm53, WilliamECrew, willicassi, Winkarst-cpu, wirdal, wixoaGit, WlarusFromDaSpace, wrexbe, wtcwr68, xkreksx, xRiriq, YanehCheck, yathxyz, Ygg01, YotaXP, youarereadingthis, Yousifb26, youtissoum, YuriyKiss, zach-hill, Zadeon, zamp, Zandario, Zap527, Zealith-Gamer, ZelteHonor, zero, ZeroDiamond, zerorulez, ZeWaka, zionnBE, ZNixian, ZoldorfTheWizard, Zonespace27, Zumorica, Zymem, zzylex From 5b295ab7c3b9af865821d67e196d6e13cf133ba5 Mon Sep 17 00:00:00 2001 From: de0rix <151521628+de0rix@users.noreply.github.com> Date: Sun, 15 Sep 2024 04:53:58 +0300 Subject: [PATCH 053/138] Fix animals sprites in critical state (#32175) Initial commit --- .../Prototypes/Entities/Mobs/NPCs/animals.yml | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml index 629f868d7e4..c06b5aacea2 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml @@ -32,6 +32,8 @@ states: Alive: Base: bat + Critical: + Base: dead Dead: Base: dead - type: Butcherable @@ -101,6 +103,8 @@ states: Alive: Base: 0 + Critical: + Base: dead Dead: Base: dead - type: Item @@ -341,6 +345,8 @@ states: Alive: Base: cockroach + Critical: + Base: cockroach_dead Dead: Base: cockroach_dead - type: Bloodstream @@ -627,6 +633,8 @@ states: Alive: Base: duck-0 + Critical: + Base: dead-0 Dead: Base: dead-0 - type: Butcherable @@ -667,6 +675,8 @@ states: Alive: Base: duck-1 + Critical: + Base: dead-1 Dead: Base: dead-1 @@ -684,6 +694,8 @@ states: Alive: Base: duck-2 + Critical: + Base: dead-2 Dead: Base: dead-2 @@ -743,6 +755,8 @@ states: Alive: Base: butterfly + Critical: + Base: dead Dead: Base: dead - type: Bloodstream @@ -789,6 +803,8 @@ states: Alive: Base: cow + Critical: + Base: dead Dead: Base: dead - type: SolutionContainerManager @@ -871,6 +887,8 @@ states: Alive: Base: crab + Critical: + Base: dead Dead: Base: dead - type: Butcherable @@ -1019,6 +1037,8 @@ states: Alive: Base: goose + Critical: + Base: dead Dead: Base: dead - type: Butcherable @@ -1879,6 +1899,8 @@ states: Alive: Base: lizard + Critical: + Base: dead Dead: Base: dead - type: Butcherable @@ -1933,6 +1955,8 @@ states: Alive: Base: slug + Critical: + Base: dead Dead: Base: dead - type: Butcherable @@ -1985,6 +2009,8 @@ states: Alive: Base: frog + Critical: + Base: dead Dead: Base: dead - type: Butcherable @@ -2035,6 +2061,8 @@ states: Alive: Base: parrot + Critical: + Base: dead Dead: Base: dead - type: Butcherable @@ -2086,6 +2114,8 @@ states: Alive: Base: penguin + Critical: + Base: penguin_dead Dead: Base: penguin_dead - type: Butcherable @@ -2155,6 +2185,8 @@ states: Alive: Base: penguin + Critical: + Base: dead Dead: Base: dead - type: MeleeWeapon @@ -2271,6 +2303,8 @@ states: Alive: Base: tarantula + Critical: + Base: tarantula_dead Dead: Base: tarantula_dead - type: Butcherable @@ -2396,6 +2430,8 @@ states: Alive: Base: clown + Critical: + Base: dead Dead: Base: dead - type: MobThresholds @@ -2465,6 +2501,8 @@ states: Alive: Base: possum + Critical: + Base: possum_dead Dead: Base: possum_dead - type: Butcherable @@ -2500,6 +2538,8 @@ states: Alive: Base: possum_old + Critical: + Base: possum_dead_old Dead: Base: possum_dead_old @@ -2534,6 +2574,8 @@ states: Alive: Base: raccoon + Critical: + Base: raccoon_dead Dead: Base: raccoon_dead - type: Butcherable @@ -2592,6 +2634,8 @@ states: Alive: Base: fox + Critical: + Base: fox_dead Dead: Base: fox_dead - type: Butcherable @@ -2663,6 +2707,8 @@ states: Alive: Base: corgi + Critical: + Base: corgi_dead Dead: Base: corgi_dead - type: Butcherable @@ -2704,6 +2750,8 @@ states: Alive: Base: narsian + Critical: + Base: narsian_dead Dead: Base: narsian_dead - type: MeleeWeapon @@ -2805,6 +2853,8 @@ states: Alive: Base: cat + Critical: + Base: cat_dead Dead: Base: cat_dead - type: Speech @@ -2855,6 +2905,8 @@ states: Alive: Base: cat2 + Critical: + Base: cat2_dead Dead: Base: cat2_dead @@ -2872,6 +2924,8 @@ states: Alive: Base: syndicat + Critical: + Base: syndicat_dead Dead: Base: syndicat_dead - type: GhostRole @@ -2917,6 +2971,8 @@ states: Alive: Base: spacecat + Critical: + Base: spacecat_dead Dead: Base: spacecat_dead - type: Temperature @@ -2954,6 +3010,8 @@ states: Alive: Base: caracal_flop + Critical: + Base: caracal_dead Dead: Base: caracal_dead @@ -3024,6 +3082,8 @@ states: Alive: Base: sloth + Critical: + Base: sloth_dead Dead: Base: sloth_dead - type: Butcherable @@ -3075,6 +3135,8 @@ states: Alive: Base: ferret + Critical: + Base: Dead: Base: ferret_dead - type: Butcherable @@ -3281,6 +3343,8 @@ states: Alive: Base: pig + Critical: + Base: Dead: Base: dead - type: Butcherable From f81d18914d158be67100c60d7c6af192f23cce29 Mon Sep 17 00:00:00 2001 From: slarticodefast <161409025+slarticodefast@users.noreply.github.com> Date: Sun, 15 Sep 2024 03:54:18 +0200 Subject: [PATCH 054/138] fix infinite banana bug (#32167) --- .../Effects/Systems/ChemicalPuddleArtifactSystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/ChemicalPuddleArtifactSystem.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/ChemicalPuddleArtifactSystem.cs index cd312797ce7..542d8bb84cc 100644 --- a/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/ChemicalPuddleArtifactSystem.cs +++ b/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/ChemicalPuddleArtifactSystem.cs @@ -18,7 +18,7 @@ public sealed class ChemicalPuddleArtifactSystem : EntitySystem /// The key for the node data entry containing /// the chemicals that the puddle is made of. /// - public const string NodeDataChemicalList = "nodeDataSpawnAmount"; + public const string NodeDataChemicalList = "nodeDataChemicalList"; /// public override void Initialize() From ee434e397d483c10b1dbf29e736de6a134e82746 Mon Sep 17 00:00:00 2001 From: nikthechampiongr <32041239+nikthechampiongr@users.noreply.github.com> Date: Sun, 15 Sep 2024 01:55:03 +0000 Subject: [PATCH 055/138] Rename fix (#31654) * Localize RenameCommand and delegate most of the process to MetaDataSystem.SetEntityName() * Make renaming rely on the EntityRenamedEvent. Fix issue where renaming would keep old Examine text Requires engine change * Fix localisation strings * Make PDA search be based on a renamed entity's Uid instead of its old name To do this the pda component now has an PdaOwner field which gets assigned when it is given as a loadout to a player * Fix bad merge??? huh * Use AllEntityQuery --- .../Administration/Systems/AdminSystem.cs | 6 ++ .../IdentityManagement/IdentitySystem.cs | 1 + Content.Server/Mind/Commands/RenameCommand.cs | 80 ++----------------- Content.Server/PDA/PdaSystem.cs | 19 ++++- .../Station/Systems/StationSpawningSystem.cs | 2 +- .../Systems/StationRecordsSystem.cs | 29 +++++++ .../Access/Systems/SharedIdCardSystem.cs | 13 +++ Content.Shared/Mind/SharedMindSystem.cs | 7 ++ .../EntitySystems/NameModifierSystem.cs | 8 +- Content.Shared/PDA/PdaComponent.cs | 4 + .../en-US/mind/commands/rename-command.ftl | 5 ++ 11 files changed, 95 insertions(+), 79 deletions(-) create mode 100644 Resources/Locale/en-US/mind/commands/rename-command.ftl diff --git a/Content.Server/Administration/Systems/AdminSystem.cs b/Content.Server/Administration/Systems/AdminSystem.cs index 99551c714c4..ce18a1e4f72 100644 --- a/Content.Server/Administration/Systems/AdminSystem.cs +++ b/Content.Server/Administration/Systems/AdminSystem.cs @@ -98,6 +98,7 @@ public override void Initialize() SubscribeLocalEvent(OnRoleEvent); SubscribeLocalEvent(OnRoleEvent); SubscribeLocalEvent(OnRoundRestartCleanup); + SubscribeLocalEvent(OnPlayerRenamed); } private void OnRoundRestartCleanup(RoundRestartCleanupEvent ev) @@ -124,6 +125,11 @@ private void OnRoundRestartCleanup(RoundRestartCleanupEvent ev) } } + private void OnPlayerRenamed(Entity ent, ref EntityRenamedEvent args) + { + UpdatePlayerList(ent.Comp.PlayerSession); + } + public void UpdatePlayerList(ICommonSession player) { _playerList[player.UserId] = GetPlayerInfo(player.Data, player); diff --git a/Content.Server/IdentityManagement/IdentitySystem.cs b/Content.Server/IdentityManagement/IdentitySystem.cs index 4766b89172f..e110a424834 100644 --- a/Content.Server/IdentityManagement/IdentitySystem.cs +++ b/Content.Server/IdentityManagement/IdentitySystem.cs @@ -39,6 +39,7 @@ public override void Initialize() SubscribeLocalEvent((uid, _, _) => QueueIdentityUpdate(uid)); SubscribeLocalEvent((uid, _, _) => QueueIdentityUpdate(uid)); SubscribeLocalEvent((uid, _, _) => QueueIdentityUpdate(uid)); + SubscribeLocalEvent((uid, _, _) => QueueIdentityUpdate(uid)); SubscribeLocalEvent(OnMapInit); } diff --git a/Content.Server/Mind/Commands/RenameCommand.cs b/Content.Server/Mind/Commands/RenameCommand.cs index 834453fb198..f283fe5d19c 100644 --- a/Content.Server/Mind/Commands/RenameCommand.cs +++ b/Content.Server/Mind/Commands/RenameCommand.cs @@ -1,31 +1,22 @@ using System.Diagnostics.CodeAnalysis; -using Content.Server.Access.Systems; using Content.Server.Administration; -using Content.Server.Administration.Systems; -using Content.Server.PDA; -using Content.Server.StationRecords.Systems; using Content.Shared.Access.Components; using Content.Shared.Administration; -using Content.Shared.Mind; -using Content.Shared.PDA; -using Content.Shared.StationRecords; using Robust.Server.Player; using Robust.Shared.Console; -using Robust.Shared.Player; namespace Content.Server.Mind.Commands; [AdminCommand(AdminFlags.VarEdit)] -public sealed class RenameCommand : IConsoleCommand +public sealed class RenameCommand : LocalizedEntityCommands { [Dependency] private readonly IEntityManager _entManager = default!; [Dependency] private readonly IPlayerManager _playerManager = default!; + [Dependency] private readonly MetaDataSystem _metaSystem = default!; - public string Command => "rename"; - public string Description => "Renames an entity and its cloner entries, ID cards, and PDAs."; - public string Help => "rename "; + public override string Command => "rename"; - public void Execute(IConsoleShell shell, string argStr, string[] args) + public override void Execute(IConsoleShell shell, string argStr, string[] args) { if (args.Length != 2) { @@ -36,69 +27,14 @@ public void Execute(IConsoleShell shell, string argStr, string[] args) var name = args[1]; if (name.Length > IdCardConsoleComponent.MaxFullNameLength) { - shell.WriteLine("Name is too long."); + shell.WriteLine(Loc.GetString("cmd-rename-too-long")); return; } if (!TryParseUid(args[0], shell, _entManager, out var entityUid)) return; - // Metadata - var metadata = _entManager.GetComponent(entityUid.Value); - var oldName = metadata.EntityName; - _entManager.System().SetEntityName(entityUid.Value, name, metadata); - - var minds = _entManager.System(); - - if (minds.TryGetMind(entityUid.Value, out var mindId, out var mind)) - { - // Mind - mind.CharacterName = name; - _entManager.Dirty(mindId, mind); - } - - // Id Cards - if (_entManager.TrySystem(out var idCardSystem)) - { - if (idCardSystem.TryFindIdCard(entityUid.Value, out var idCard)) - { - idCardSystem.TryChangeFullName(idCard, name, idCard); - - // Records - // This is done here because ID cards are linked to station records - if (_entManager.TrySystem(out var recordsSystem) - && _entManager.TryGetComponent(idCard, out StationRecordKeyStorageComponent? keyStorage) - && keyStorage.Key is {} key) - { - if (recordsSystem.TryGetRecord(key, out var generalRecord)) - { - generalRecord.Name = name; - } - - recordsSystem.Synchronize(key); - } - } - } - - // PDAs - if (_entManager.TrySystem(out var pdaSystem)) - { - var query = _entManager.EntityQueryEnumerator(); - while (query.MoveNext(out var uid, out var pda)) - { - if (pda.OwnerName == oldName) - { - pdaSystem.SetOwner(uid, pda, name); - } - } - } - - // Admin Overlay - if (_entManager.TrySystem(out var adminSystem) - && _entManager.TryGetComponent(entityUid, out var actorComp)) - { - adminSystem.UpdatePlayerList(actorComp.PlayerSession); - } + _metaSystem.SetEntityName(entityUid.Value, name); } private bool TryParseUid(string str, IConsoleShell shell, @@ -114,9 +50,9 @@ private bool TryParseUid(string str, IConsoleShell shell, } if (session == null) - shell.WriteError("Can't find username/uid: " + str); + shell.WriteError(Loc.GetString("cmd-rename-not-found", ("target", str))); else - shell.WriteError(str + " does not have an entity."); + shell.WriteError(Loc.GetString("cmd-rename-no-entity", ("target", str))); entityUid = EntityUid.Invalid; return false; diff --git a/Content.Server/PDA/PdaSystem.cs b/Content.Server/PDA/PdaSystem.cs index 691d024ecd7..cdcdbc02e5f 100644 --- a/Content.Server/PDA/PdaSystem.cs +++ b/Content.Server/PDA/PdaSystem.cs @@ -55,9 +55,23 @@ public override void Initialize() SubscribeLocalEvent(OnNotification); SubscribeLocalEvent(OnStationRenamed); + SubscribeLocalEvent(OnEntityRenamed); SubscribeLocalEvent(OnAlertLevelChanged); } + private void OnEntityRenamed(ref EntityRenamedEvent ev) + { + var query = EntityQueryEnumerator(); + + while (query.MoveNext(out var uid, out var comp)) + { + if (comp.PdaOwner == ev.Uid) + { + SetOwner(uid, comp, ev.Uid, ev.NewName); + } + } + } + protected override void OnComponentInit(EntityUid uid, PdaComponent pda, ComponentInit args) { base.OnComponentInit(uid, pda, args); @@ -94,9 +108,10 @@ private void OnLightToggle(EntityUid uid, PdaComponent pda, LightToggleEvent arg UpdatePdaUi(uid, pda); } - public void SetOwner(EntityUid uid, PdaComponent pda, string ownerName) + public void SetOwner(EntityUid uid, PdaComponent pda, EntityUid owner, string ownerName) { pda.OwnerName = ownerName; + pda.PdaOwner = owner; UpdatePdaUi(uid, pda); } @@ -112,7 +127,7 @@ private void OnAlertLevelChanged(AlertLevelChangedEvent args) private void UpdateAllPdaUisOnStation() { - var query = EntityQueryEnumerator(); + var query = AllEntityQuery(); while (query.MoveNext(out var ent, out var comp)) { UpdatePdaUi(ent, comp); diff --git a/Content.Server/Station/Systems/StationSpawningSystem.cs b/Content.Server/Station/Systems/StationSpawningSystem.cs index 88e2b08cb4e..e39a0943199 100644 --- a/Content.Server/Station/Systems/StationSpawningSystem.cs +++ b/Content.Server/Station/Systems/StationSpawningSystem.cs @@ -246,7 +246,7 @@ public void SetPdaAndIdCardData(EntityUid entity, string characterName, JobProto _accessSystem.SetAccessToJob(cardId, jobPrototype, extendedAccess); if (pdaComponent != null) - _pdaSystem.SetOwner(idUid.Value, pdaComponent, characterName); + _pdaSystem.SetOwner(idUid.Value, pdaComponent, entity, characterName); } diff --git a/Content.Server/StationRecords/Systems/StationRecordsSystem.cs b/Content.Server/StationRecords/Systems/StationRecordsSystem.cs index c7d56654646..e941e65c415 100644 --- a/Content.Server/StationRecords/Systems/StationRecordsSystem.cs +++ b/Content.Server/StationRecords/Systems/StationRecordsSystem.cs @@ -1,6 +1,9 @@ using System.Diagnostics.CodeAnalysis; +using System.IO; +using Content.Server.Access.Systems; using Content.Server.Forensics; using Content.Server.GameTicking; +using Content.Shared.Access.Components; using Content.Shared.Inventory; using Content.Shared.PDA; using Content.Shared.Preferences; @@ -35,12 +38,14 @@ public sealed class StationRecordsSystem : SharedStationRecordsSystem [Dependency] private readonly InventorySystem _inventory = default!; [Dependency] private readonly StationRecordKeyStorageSystem _keyStorage = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly IdCardSystem _idCard = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnPlayerSpawn); + SubscribeLocalEvent(OnRename); } private void OnPlayerSpawn(PlayerSpawnCompleteEvent args) @@ -51,6 +56,30 @@ private void OnPlayerSpawn(PlayerSpawnCompleteEvent args) CreateGeneralRecord(args.Station, args.Mob, args.Profile, args.JobId, stationRecords); } + private void OnRename(ref EntityRenamedEvent ev) + { + // When a player gets renamed their card gets changed to match. + // Unfortunately this means that an event is called for it as well, and since TryFindIdCard will succeed if the + // given entity is a card and the card itself is the key the record will be mistakenly renamed to the card's name + // if we don't return early. + if (HasComp(ev.Uid)) + return; + + if (_idCard.TryFindIdCard(ev.Uid, out var idCard)) + { + if (TryComp(idCard, out StationRecordKeyStorageComponent? keyStorage) + && keyStorage.Key is {} key) + { + if (TryGetRecord(key, out var generalRecord)) + { + generalRecord.Name = ev.NewName; + } + + Synchronize(key); + } + } + } + private void CreateGeneralRecord(EntityUid station, EntityUid player, HumanoidCharacterProfile profile, string? jobId, StationRecordsComponent records) { diff --git a/Content.Shared/Access/Systems/SharedIdCardSystem.cs b/Content.Shared/Access/Systems/SharedIdCardSystem.cs index 5a90d4ea355..8bdc548e353 100644 --- a/Content.Shared/Access/Systems/SharedIdCardSystem.cs +++ b/Content.Shared/Access/Systems/SharedIdCardSystem.cs @@ -25,6 +25,19 @@ public override void Initialize() SubscribeLocalEvent(OnMapInit); SubscribeLocalEvent(OnTryGetIdentityShortInfo); + SubscribeLocalEvent(OnRename); + } + + private void OnRename(ref EntityRenamedEvent ev) + { + // When a player gets renamed their id card is renamed as well to match. + // Unfortunately since TryFindIdCard will succeed if the entity is also a card this means that the card will + // keep renaming itself unless we return early. + if (HasComp(ev.Uid)) + return; + + if (TryFindIdCard(ev.Uid, out var idCard)) + TryChangeFullName(idCard, ev.NewName, idCard); } private void OnMapInit(EntityUid uid, IdCardComponent id, MapInitEvent args) diff --git a/Content.Shared/Mind/SharedMindSystem.cs b/Content.Shared/Mind/SharedMindSystem.cs index c8e1c1a4b3a..162bca495ca 100644 --- a/Content.Shared/Mind/SharedMindSystem.cs +++ b/Content.Shared/Mind/SharedMindSystem.cs @@ -39,6 +39,7 @@ public override void Initialize() SubscribeLocalEvent(OnVisitingTerminating); SubscribeLocalEvent(OnReset); SubscribeLocalEvent(OnMindStartup); + SubscribeLocalEvent(OnRenamed); } public override void Shutdown() @@ -181,6 +182,12 @@ private void OnSuicide(EntityUid uid, MindContainerComponent component, SuicideE args.Handled = true; } + private void OnRenamed(Entity ent, ref EntityRenamedEvent args) + { + ent.Comp.CharacterName = args.NewName; + Dirty(ent); + } + public EntityUid? GetMind(EntityUid uid, MindContainerComponent? mind = null) { if (!Resolve(uid, ref mind)) diff --git a/Content.Shared/NameModifier/EntitySystems/NameModifierSystem.cs b/Content.Shared/NameModifier/EntitySystems/NameModifierSystem.cs index 4dffb51805c..2e7c8054b3b 100644 --- a/Content.Shared/NameModifier/EntitySystems/NameModifierSystem.cs +++ b/Content.Shared/NameModifier/EntitySystems/NameModifierSystem.cs @@ -5,7 +5,7 @@ namespace Content.Shared.NameModifier.EntitySystems; /// -public sealed partial class NameModifierSystem : EntitySystem +public sealed class NameModifierSystem : EntitySystem { [Dependency] private readonly MetaDataSystem _metaData = default!; @@ -16,10 +16,10 @@ public override void Initialize() SubscribeLocalEvent(OnEntityRenamed); } - private void OnEntityRenamed(Entity entity, ref EntityRenamedEvent args) + private void OnEntityRenamed(Entity ent, ref EntityRenamedEvent args) { - SetBaseName((entity, entity.Comp), args.NewName); - RefreshNameModifiers((entity, entity.Comp)); + SetBaseName(ent, args.NewName); + RefreshNameModifiers((ent.Owner, ent.Comp)); } private void SetBaseName(Entity entity, string name) diff --git a/Content.Shared/PDA/PdaComponent.cs b/Content.Shared/PDA/PdaComponent.cs index d4cfc4fc0d8..6aeb245e27d 100644 --- a/Content.Shared/PDA/PdaComponent.cs +++ b/Content.Shared/PDA/PdaComponent.cs @@ -37,6 +37,10 @@ public sealed partial class PdaComponent : Component [ViewVariables] public bool FlashlightOn; [ViewVariables(VVAccess.ReadWrite)] public string? OwnerName; + // The Entity that "owns" the PDA, usually a player's character. + // This is useful when we are doing stuff like renaming a player and want to find their PDA to change the name + // as well. + [ViewVariables(VVAccess.ReadWrite)] public EntityUid? PdaOwner; [ViewVariables] public string? StationName; [ViewVariables] public string? StationAlertLevel; [ViewVariables] public Color StationAlertColor = Color.White; diff --git a/Resources/Locale/en-US/mind/commands/rename-command.ftl b/Resources/Locale/en-US/mind/commands/rename-command.ftl new file mode 100644 index 00000000000..4749cd6379e --- /dev/null +++ b/Resources/Locale/en-US/mind/commands/rename-command.ftl @@ -0,0 +1,5 @@ +cmd-rename-desc = Renames an entity and its cloner entries, ID cards, and PDAs. +cmd-rename-help = rename +cmd-rename-too-long = Name is too long. +cmd-rename-not-found = Can't find username/uid: {$target} +cmd-rename-no-entity = {$target} does not have an entity. From 6766be541a1867fa49873f0bc9aec018645f92be Mon Sep 17 00:00:00 2001 From: PJBot Date: Sun, 15 Sep 2024 01:55:04 +0000 Subject: [PATCH 056/138] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 2215566c344..ecfd447d09f 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Beck Thompson - changes: - - message: Splashing reagents on players will now apply the correct amounts. - type: Fix - id: 6876 - time: '2024-07-07T03:52:18.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29763 - author: Tayrtahn changes: - message: Dead bodies will no longer remain standing after being unbuckled from @@ -3919,3 +3912,10 @@ id: 7375 time: '2024-09-14T20:40:38.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/32169 +- author: de0rix + changes: + - message: Animals in critical state now all have proper sprites. + type: Fix + id: 7376 + time: '2024-09-15T01:53:58.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/32175 From d015291c52bf4c25cbf43b76fd68f30a4a975ad6 Mon Sep 17 00:00:00 2001 From: PJBot Date: Sun, 15 Sep 2024 01:56:14 +0000 Subject: [PATCH 057/138] Automatic changelog update --- Resources/Changelog/Admin.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Resources/Changelog/Admin.yml b/Resources/Changelog/Admin.yml index 3951dd6e861..c5b567f69e3 100644 --- a/Resources/Changelog/Admin.yml +++ b/Resources/Changelog/Admin.yml @@ -534,5 +534,15 @@ Entries: id: 66 time: '2024-09-13T22:49:27.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/32125 +- author: nikthechampiongr + changes: + - message: Rename verb now acts the same as the rename command. + type: Fix + - message: Renamed entities will now have their new name appear immediately on entity + examination and on crew monitor console. + type: Fix + id: 67 + time: '2024-09-15T01:55:03.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/31654 Name: Admin Order: 1 From 30c5fbb0be7269accc58644c300f5c5372b5f181 Mon Sep 17 00:00:00 2001 From: Partmedia Date: Sat, 14 Sep 2024 17:58:10 -0800 Subject: [PATCH 058/138] Make pressure and volume pumps require power (#28995) --- .../Binary/EntitySystems/GasPressurePumpSystem.cs | 11 ++++++++++- .../Binary/EntitySystems/GasVolumePumpSystem.cs | 11 ++++++++++- .../Structures/Piping/Atmospherics/binary.yml | 14 ++++++++++++-- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasPressurePumpSystem.cs b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasPressurePumpSystem.cs index 871c84e0588..56359a85af5 100644 --- a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasPressurePumpSystem.cs +++ b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasPressurePumpSystem.cs @@ -5,6 +5,7 @@ using Content.Server.NodeContainer; using Content.Server.NodeContainer.EntitySystems; using Content.Server.NodeContainer.Nodes; +using Content.Server.Power.Components; using Content.Shared.Atmos; using Content.Shared.Atmos.Piping; using Content.Shared.Atmos.Piping.Binary.Components; @@ -39,6 +40,7 @@ public override void Initialize() SubscribeLocalEvent(OnPumpLeaveAtmosphere); SubscribeLocalEvent(OnExamined); SubscribeLocalEvent(OnPumpActivate); + SubscribeLocalEvent(OnPowerChanged); // Bound UI subscriptions SubscribeLocalEvent(OnOutputPressureChangeMessage); SubscribeLocalEvent(OnToggleStatusMessage); @@ -63,9 +65,15 @@ private void OnExamined(EntityUid uid, GasPressurePumpComponent pump, ExaminedEv } } + private void OnPowerChanged(EntityUid uid, GasPressurePumpComponent component, ref PowerChangedEvent args) + { + UpdateAppearance(uid, component); + } + private void OnPumpUpdated(EntityUid uid, GasPressurePumpComponent pump, ref AtmosDeviceUpdateEvent args) { if (!pump.Enabled + || (TryComp(uid, out var power) && !power.Powered) || !_nodeContainer.TryGetNodes(uid, pump.InletName, pump.OutletName, out PipeNode? inlet, out PipeNode? outlet)) { _ambientSoundSystem.SetAmbience(uid, false); @@ -154,7 +162,8 @@ private void UpdateAppearance(EntityUid uid, GasPressurePumpComponent? pump = nu if (!Resolve(uid, ref pump, ref appearance, false)) return; - _appearance.SetData(uid, PumpVisuals.Enabled, pump.Enabled, appearance); + bool pumpOn = pump.Enabled && (TryComp(uid, out var power) && power.Powered); + _appearance.SetData(uid, PumpVisuals.Enabled, pumpOn, appearance); } } } diff --git a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs index d9fbeb474e2..d1127920514 100644 --- a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs +++ b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs @@ -9,6 +9,7 @@ using Content.Server.NodeContainer; using Content.Server.NodeContainer.EntitySystems; using Content.Server.NodeContainer.Nodes; +using Content.Server.Power.Components; using Content.Shared.Atmos.Piping.Binary.Components; using Content.Shared.Atmos.Visuals; using Content.Shared.Audio; @@ -45,6 +46,7 @@ public override void Initialize() SubscribeLocalEvent(OnVolumePumpLeaveAtmosphere); SubscribeLocalEvent(OnExamined); SubscribeLocalEvent(OnPumpActivate); + SubscribeLocalEvent(OnPowerChanged); // Bound UI subscriptions SubscribeLocalEvent(OnTransferRateChangeMessage); SubscribeLocalEvent(OnToggleStatusMessage); @@ -69,9 +71,15 @@ private void OnExamined(EntityUid uid, GasVolumePumpComponent pump, ExaminedEven args.PushMarkup(str); } + private void OnPowerChanged(EntityUid uid, GasVolumePumpComponent component, ref PowerChangedEvent args) + { + UpdateAppearance(uid, component); + } + private void OnVolumePumpUpdated(EntityUid uid, GasVolumePumpComponent pump, ref AtmosDeviceUpdateEvent args) { if (!pump.Enabled || + (TryComp(uid, out var power) && !power.Powered) || !_nodeContainer.TryGetNodes(uid, pump.InletName, pump.OutletName, out PipeNode? inlet, out PipeNode? outlet)) { _ambientSoundSystem.SetAmbience(uid, false); @@ -183,7 +191,8 @@ private void UpdateAppearance(EntityUid uid, GasVolumePumpComponent? pump = null if (!Resolve(uid, ref pump, ref appearance, false)) return; - if (!pump.Enabled) + bool pumpOn = pump.Enabled && (TryComp(uid, out var power) && power.Powered); + if (!pumpOn) _appearance.SetData(uid, GasVolumePumpVisuals.State, GasVolumePumpState.Off, appearance); else if (pump.Blocked) _appearance.SetData(uid, GasVolumePumpVisuals.State, GasVolumePumpState.Blocked, appearance); diff --git a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/binary.yml b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/binary.yml index 24a8cb58da0..ba86ca65a06 100644 --- a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/binary.yml +++ b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/binary.yml @@ -24,13 +24,18 @@ pipeDirection: South - type: entity - parent: GasBinaryBase + parent: [BaseMachinePowered, GasBinaryBase] id: GasPressurePump name: gas pump description: A pump that moves gas by pressure. placement: mode: SnapgridCenter components: + - type: ApcPowerReceiver + powerLoad: 200 + - type: Rotatable + - type: Transform + noRot: false - type: Sprite sprite: Structures/Piping/Atmospherics/pump.rsi layers: @@ -64,13 +69,18 @@ path: /Audio/Ambience/Objects/gas_pump.ogg - type: entity - parent: GasBinaryBase + parent: [BaseMachinePowered, GasBinaryBase] id: GasVolumePump name: volumetric gas pump description: A pump that moves gas by volume. placement: mode: SnapgridCenter components: + - type: ApcPowerReceiver + powerLoad: 200 + - type: Rotatable + - type: Transform + noRot: false - type: Sprite sprite: Structures/Piping/Atmospherics/pump.rsi layers: From 823511c517d2e854a523fad8fcadf5b4d824caa2 Mon Sep 17 00:00:00 2001 From: PJBot Date: Sun, 15 Sep 2024 01:59:16 +0000 Subject: [PATCH 059/138] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index ecfd447d09f..1c8aac9c76f 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: Tayrtahn - changes: - - message: Dead bodies will no longer remain standing after being unbuckled from - chairs. - type: Fix - id: 6877 - time: '2024-07-07T06:20:53.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29741 - author: Simyon changes: - message: Ratkings now require at least 30 players in order to spawn. @@ -3919,3 +3911,10 @@ id: 7376 time: '2024-09-15T01:53:58.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/32175 +- author: notafet + changes: + - message: Pressure and volume pumps now require power to operate. + type: Tweak + id: 7377 + time: '2024-09-15T01:58:10.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/28995 From 62eaae650454bc443a9a65056f1f3b5e1577a949 Mon Sep 17 00:00:00 2001 From: Winkarst <74284083+Winkarst-cpu@users.noreply.github.com> Date: Sun, 15 Sep 2024 05:08:54 +0300 Subject: [PATCH 060/138] Update SharedBuckleSystem to use PopupClient (#31498) --- .../Buckle/SharedBuckleSystem.Buckle.cs | 47 ++++++++++--------- Content.Shared/Buckle/SharedBuckleSystem.cs | 2 - 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs b/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs index 83c24016ceb..7f6c39eafc0 100644 --- a/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs +++ b/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs @@ -242,8 +242,9 @@ private bool CanBuckle(EntityUid buckleUid, if (_whitelistSystem.IsWhitelistFail(strapComp.Whitelist, buckleUid) || _whitelistSystem.IsBlacklistPass(strapComp.Blacklist, buckleUid)) { - if (_netManager.IsServer && popup && user != null) - _popup.PopupEntity(Loc.GetString("buckle-component-cannot-fit-message"), user.Value, user.Value, PopupType.Medium); + if (popup) + _popup.PopupClient(Loc.GetString("buckle-component-cannot-fit-message"), user, PopupType.Medium); + return false; } @@ -261,23 +262,24 @@ private bool CanBuckle(EntityUid buckleUid, if (user != null && !HasComp(user)) { - // PopupPredicted when - if (_netManager.IsServer && popup) - _popup.PopupEntity(Loc.GetString("buckle-component-no-hands-message"), user.Value, user.Value); + if (popup) + _popup.PopupClient(Loc.GetString("buckle-component-no-hands-message"), user); + return false; } if (buckleComp.Buckled) { - if (_netManager.IsClient || popup || user == null) - return false; - - var message = Loc.GetString(buckleUid == user + if (popup) + { + var message = Loc.GetString(buckleUid == user ? "buckle-component-already-buckled-message" : "buckle-component-other-already-buckled-message", ("owner", Identity.Entity(buckleUid, EntityManager))); - _popup.PopupEntity(message, user.Value, user.Value); + _popup.PopupClient(message, user); + } + return false; } @@ -291,29 +293,30 @@ private bool CanBuckle(EntityUid buckleUid, continue; } - if (_netManager.IsClient || popup || user == null) - return false; - - var message = Loc.GetString(buckleUid == user + if (popup) + { + var message = Loc.GetString(buckleUid == user ? "buckle-component-cannot-buckle-message" : "buckle-component-other-cannot-buckle-message", ("owner", Identity.Entity(buckleUid, EntityManager))); - _popup.PopupEntity(message, user.Value, user.Value); + _popup.PopupClient(message, user); + } + return false; } if (!StrapHasSpace(strapUid, buckleComp, strapComp)) { - if (_netManager.IsClient || popup || user == null) - return false; - - var message = Loc.GetString(buckleUid == user - ? "buckle-component-cannot-fit-message" - : "buckle-component-other-cannot-fit-message", + if (popup) + { + var message = Loc.GetString(buckleUid == user + ? "buckle-component-cannot-buckle-message" + : "buckle-component-other-cannot-buckle-message", ("owner", Identity.Entity(buckleUid, EntityManager))); - _popup.PopupEntity(message, user.Value, user.Value); + _popup.PopupClient(message, user); + } return false; } diff --git a/Content.Shared/Buckle/SharedBuckleSystem.cs b/Content.Shared/Buckle/SharedBuckleSystem.cs index d190f685ed0..da1d111f977 100644 --- a/Content.Shared/Buckle/SharedBuckleSystem.cs +++ b/Content.Shared/Buckle/SharedBuckleSystem.cs @@ -9,7 +9,6 @@ using Content.Shared.Standing; using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; -using Robust.Shared.Network; using Robust.Shared.Physics.Systems; using Robust.Shared.Player; using Robust.Shared.Timing; @@ -18,7 +17,6 @@ namespace Content.Shared.Buckle; public abstract partial class SharedBuckleSystem : EntitySystem { - [Dependency] private readonly INetManager _netManager = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; [Dependency] private readonly ISharedPlayerManager _playerManager = default!; From 1dec19cc052dd22c73cc25dc92b3d0a918ef13fd Mon Sep 17 00:00:00 2001 From: drakewill-CRL <46307022+drakewill-CRL@users.noreply.github.com> Date: Sat, 14 Sep 2024 23:12:17 -0400 Subject: [PATCH 061/138] Botany Rework Part 1: Mutations (#31163) Instead of each mutation being a flag that gets checked at some unique point in BotanySystem somewhere, they're now EntityEffects that get applied when the mutation occurs and when produce is harvested. One new list was added to SeedData so that multiple other fields could be removed. All the non-stat-change mutations that have been rolled are added to the Mutations list, and get applied to the plant when the mutation occurs or when a seed with the mutation is planted. Produce get mutations applied at harvest if they apply to the produce, and carry all of the plant's mutations over as a seed. This gets rid of the one-off checks for things like Slippery, Bioluminescent, Sentient, etc. The base odds of a mutation applying should be equal to the odds of the original mutation check. It pretended to have 1 bit flip (on averge) per mutation power, and odds of each mutation was the odds of one of its bit being flipped (1 /275 * bits). The 'thermometer code' applied for numbers will be replaced with simple random rolls, as both average out to the middle value. The new checks are much easier to understand and don't obfuscate the actual changes of something happening behind 3 layers of math. The biggest player-facing change is that Potency will be able to get over 65 significantly more often than it did in the previous system, but it will be just as common to get low values as high ones. Mutation definitions have been moved to a .yml file. These include the odds per tick per mutagen strength of that mutation applying that tick, the effect applied, if it applies to the plant and/or its produce. This makes mutations simpler to add and edit. This PR is limited specifically to the mutation logic. Improving other aspects of the system will be done in other PRs per the design document. Mutations was chosen first because its got the largest amount of one-off checks scattered all over that could be consolidated. Once this is merged, mutations could be contributed to the codebase with minimal extra work for later botany refactor PRs. --- .../Botany/Components/PlantHolderComponent.cs | 58 ++-- .../Botany/Components/ProduceComponent.cs | 4 +- Content.Server/Botany/SeedPrototype.cs | 102 +++--- .../Botany/Systems/BotanySystem.Produce.cs | 10 + .../Botany/Systems/BotanySystem.Seed.cs | 30 -- .../Botany/Systems/MutationSystem.cs | 306 ++---------------- .../Botany/Systems/PlantHolderSystem.cs | 50 +-- .../Botany/Systems/SeedExtractorSystem.cs | 6 - Content.Server/EntityEffects/Effects/Glow.cs | 48 +++ .../EntityEffects/Effects/PlantChangeStat.cs | 142 ++++++++ .../Effects/PlantMutateChemicals.cs | 55 ++++ .../EntityEffects/Effects/PlantMutateGases.cs | 87 +++++ .../Effects/PlantMutateHarvest.cs | 30 ++ .../Effects/PlantSpeciesChange.cs | 43 +++ .../EntityEffects/Effects/Slipify.cs | 38 +++ Content.Shared/Random/RandomPlantMutation.cs | 48 +++ .../RandomPlantMutationListPrototype.cs | 18 ++ .../{mutations.yml => randomChemicals.yml} | 0 .../Hydroponics/randomMutations.yml | 178 ++++++++++ 19 files changed, 812 insertions(+), 441 deletions(-) create mode 100644 Content.Server/EntityEffects/Effects/Glow.cs create mode 100644 Content.Server/EntityEffects/Effects/PlantChangeStat.cs create mode 100644 Content.Server/EntityEffects/Effects/PlantMutateChemicals.cs create mode 100644 Content.Server/EntityEffects/Effects/PlantMutateGases.cs create mode 100644 Content.Server/EntityEffects/Effects/PlantMutateHarvest.cs create mode 100644 Content.Server/EntityEffects/Effects/PlantSpeciesChange.cs create mode 100644 Content.Server/EntityEffects/Effects/Slipify.cs create mode 100644 Content.Shared/Random/RandomPlantMutation.cs create mode 100644 Content.Shared/Random/RandomPlantMutationListPrototype.cs rename Resources/Prototypes/Hydroponics/{mutations.yml => randomChemicals.yml} (100%) create mode 100644 Resources/Prototypes/Hydroponics/randomMutations.yml diff --git a/Content.Server/Botany/Components/PlantHolderComponent.cs b/Content.Server/Botany/Components/PlantHolderComponent.cs index 809af737ac6..8218bead72c 100644 --- a/Content.Server/Botany/Components/PlantHolderComponent.cs +++ b/Content.Server/Botany/Components/PlantHolderComponent.cs @@ -6,90 +6,90 @@ namespace Content.Server.Botany.Components; [RegisterComponent] public sealed partial class PlantHolderComponent : Component { - [DataField("nextUpdate", customTypeSerializer: typeof(TimeOffsetSerializer))] + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] public TimeSpan NextUpdate = TimeSpan.Zero; - [ViewVariables(VVAccess.ReadWrite), DataField("updateDelay")] + [DataField] public TimeSpan UpdateDelay = TimeSpan.FromSeconds(3); - [DataField("lastProduce")] + [DataField] public int LastProduce; - [ViewVariables(VVAccess.ReadWrite), DataField("missingGas")] + [DataField] public int MissingGas; - [DataField("cycleDelay")] + [DataField] public TimeSpan CycleDelay = TimeSpan.FromSeconds(15f); - [DataField("lastCycle", customTypeSerializer: typeof(TimeOffsetSerializer))] + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] public TimeSpan LastCycle = TimeSpan.Zero; - [ViewVariables(VVAccess.ReadWrite), DataField("updateSpriteAfterUpdate")] + [DataField] public bool UpdateSpriteAfterUpdate; - [ViewVariables(VVAccess.ReadWrite), DataField("drawWarnings")] + [DataField] public bool DrawWarnings = false; - [ViewVariables(VVAccess.ReadWrite), DataField("waterLevel")] + [DataField] public float WaterLevel = 100f; - [ViewVariables(VVAccess.ReadWrite), DataField("nutritionLevel")] + [DataField] public float NutritionLevel = 100f; - [ViewVariables(VVAccess.ReadWrite), DataField("pestLevel")] + [DataField] public float PestLevel; - [ViewVariables(VVAccess.ReadWrite), DataField("weedLevel")] + [DataField] public float WeedLevel; - [ViewVariables(VVAccess.ReadWrite), DataField("toxins")] + [DataField] public float Toxins; - [ViewVariables(VVAccess.ReadWrite), DataField("age")] + [DataField] public int Age; - [ViewVariables(VVAccess.ReadWrite), DataField("skipAging")] + [DataField] public int SkipAging; - [ViewVariables(VVAccess.ReadWrite), DataField("dead")] + [DataField] public bool Dead; - [ViewVariables(VVAccess.ReadWrite), DataField("harvest")] + [DataField] public bool Harvest; - [ViewVariables(VVAccess.ReadWrite), DataField("sampled")] + [DataField] public bool Sampled; - [ViewVariables(VVAccess.ReadWrite), DataField("yieldMod")] + [DataField] public int YieldMod = 1; - [ViewVariables(VVAccess.ReadWrite), DataField("mutationMod")] + [DataField] public float MutationMod = 1f; - [ViewVariables(VVAccess.ReadWrite), DataField("mutationLevel")] + [DataField] public float MutationLevel; - [ViewVariables(VVAccess.ReadWrite), DataField("health")] + [DataField] public float Health; - [ViewVariables(VVAccess.ReadWrite), DataField("weedCoefficient")] + [DataField] public float WeedCoefficient = 1f; - [ViewVariables(VVAccess.ReadWrite), DataField("seed")] + [DataField] public SeedData? Seed; - [ViewVariables(VVAccess.ReadWrite), DataField("improperHeat")] + [DataField] public bool ImproperHeat; - [ViewVariables(VVAccess.ReadWrite), DataField("improperPressure")] + [DataField] public bool ImproperPressure; - [ViewVariables(VVAccess.ReadWrite), DataField("improperLight")] + [DataField] public bool ImproperLight; - [ViewVariables(VVAccess.ReadWrite), DataField("forceUpdate")] + [DataField] public bool ForceUpdate; - [ViewVariables(VVAccess.ReadWrite), DataField("solution")] + [DataField] public string SoilSolutionName = "soil"; [DataField] diff --git a/Content.Server/Botany/Components/ProduceComponent.cs b/Content.Server/Botany/Components/ProduceComponent.cs index b3c4e1c95a9..db4ed62dd38 100644 --- a/Content.Server/Botany/Components/ProduceComponent.cs +++ b/Content.Server/Botany/Components/ProduceComponent.cs @@ -13,12 +13,12 @@ public sealed partial class ProduceComponent : SharedProduceComponent /// /// Seed data used to create a when this produce has its seeds extracted. /// - [DataField("seed")] + [DataField] public SeedData? Seed; /// /// Seed data used to create a when this produce has its seeds extracted. /// - [DataField("seedId", customTypeSerializer: typeof(PrototypeIdSerializer))] + [DataField(customTypeSerializer: typeof(PrototypeIdSerializer))] public string? SeedId; } diff --git a/Content.Server/Botany/SeedPrototype.cs b/Content.Server/Botany/SeedPrototype.cs index 39f06a64360..7a3e08883de 100644 --- a/Content.Server/Botany/SeedPrototype.cs +++ b/Content.Server/Botany/SeedPrototype.cs @@ -2,6 +2,7 @@ using Content.Server.Botany.Systems; using Content.Shared.Atmos; using Content.Shared.EntityEffects; +using Content.Shared.Random; using Robust.Shared.Audio; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; @@ -132,78 +133,67 @@ public partial class SeedData [DataField("productPrototypes", customTypeSerializer: typeof(PrototypeIdListSerializer))] public List ProductPrototypes = new(); - [DataField("chemicals")] public Dictionary Chemicals = new(); + [DataField] public Dictionary Chemicals = new(); - [DataField("consumeGasses")] public Dictionary ConsumeGasses = new(); + [DataField] public Dictionary ConsumeGasses = new(); - [DataField("exudeGasses")] public Dictionary ExudeGasses = new(); + [DataField] public Dictionary ExudeGasses = new(); #endregion #region Tolerances - [DataField("nutrientConsumption")] public float NutrientConsumption = 0.75f; + [DataField] public float NutrientConsumption = 0.75f; - [DataField("waterConsumption")] public float WaterConsumption = 0.5f; - [DataField("idealHeat")] public float IdealHeat = 293f; - [DataField("heatTolerance")] public float HeatTolerance = 10f; - [DataField("idealLight")] public float IdealLight = 7f; - [DataField("lightTolerance")] public float LightTolerance = 3f; - [DataField("toxinsTolerance")] public float ToxinsTolerance = 4f; + [DataField] public float WaterConsumption = 0.5f; + [DataField] public float IdealHeat = 293f; + [DataField] public float HeatTolerance = 10f; + [DataField] public float IdealLight = 7f; + [DataField] public float LightTolerance = 3f; + [DataField] public float ToxinsTolerance = 4f; - [DataField("lowPressureTolerance")] public float LowPressureTolerance = 81f; + [DataField] public float LowPressureTolerance = 81f; - [DataField("highPressureTolerance")] public float HighPressureTolerance = 121f; + [DataField] public float HighPressureTolerance = 121f; - [DataField("pestTolerance")] public float PestTolerance = 5f; + [DataField] public float PestTolerance = 5f; - [DataField("weedTolerance")] public float WeedTolerance = 5f; + [DataField] public float WeedTolerance = 5f; - [DataField("weedHighLevelThreshold")] public float WeedHighLevelThreshold = 10f; + [DataField] public float WeedHighLevelThreshold = 10f; #endregion #region General traits - [DataField("endurance")] public float Endurance = 100f; + [DataField] public float Endurance = 100f; - [DataField("yield")] public int Yield; - [DataField("lifespan")] public float Lifespan; - [DataField("maturation")] public float Maturation; - [DataField("production")] public float Production; - [DataField("growthStages")] public int GrowthStages = 6; + [DataField] public int Yield; + [DataField] public float Lifespan; + [DataField] public float Maturation; + [DataField] public float Production; + [DataField] public int GrowthStages = 6; - [ViewVariables(VVAccess.ReadWrite)] - [DataField("harvestRepeat")] public HarvestType HarvestRepeat = HarvestType.NoRepeat; + [DataField] public HarvestType HarvestRepeat = HarvestType.NoRepeat; - [DataField("potency")] public float Potency = 1f; + [DataField] public float Potency = 1f; /// /// If true, cannot be harvested for seeds. Balances hybrids and /// mutations. /// - [DataField("seedless")] public bool Seedless = false; + [DataField] public bool Seedless = false; /// /// If false, rapidly decrease health while growing. Used to kill off /// plants with "bad" mutations. /// - [DataField("viable")] public bool Viable = true; - - /// - /// If true, fruit slips players. - /// - [DataField("slip")] public bool Slip = false; - - /// - /// If true, fruits are sentient. - /// - [DataField("sentient")] public bool Sentient = false; + [DataField] public bool Viable = true; /// /// If true, a sharp tool is required to harvest this plant. /// - [DataField("ligneous")] public bool Ligneous; + [DataField] public bool Ligneous; // No, I'm not removing these. // if you re-add these, make sure that they get cloned. @@ -222,36 +212,35 @@ public partial class SeedData #region Cosmetics - [DataField("plantRsi", required: true)] + [DataField(required: true)] public ResPath PlantRsi { get; set; } = default!; - [DataField("plantIconState")] public string PlantIconState { get; set; } = "produce"; + [DataField] public string PlantIconState { get; set; } = "produce"; /// - /// Screams random sound, could be strict sound SoundPathSpecifier or collection SoundCollectionSpecifier - /// base class is SoundSpecifier + /// Screams random sound from collection SoundCollectionSpecifier /// - [DataField("screamSound")] + [DataField] public SoundSpecifier ScreamSound = new SoundCollectionSpecifier("PlantScreams", AudioParams.Default.WithVolume(-10)); [DataField("screaming")] public bool CanScream; - [DataField("bioluminescent")] public bool Bioluminescent; - [DataField("bioluminescentColor")] public Color BioluminescentColor { get; set; } = Color.White; + [DataField(customTypeSerializer: typeof(PrototypeIdSerializer))] public string KudzuPrototype = "WeakKudzu"; - public float BioluminescentRadius = 2f; - - [DataField("kudzuPrototype", customTypeSerializer: typeof(PrototypeIdSerializer))] public string KudzuPrototype = "WeakKudzu"; - - [DataField("turnIntoKudzu")] public bool TurnIntoKudzu; - [DataField("splatPrototype")] public string? SplatPrototype { get; set; } + [DataField] public bool TurnIntoKudzu; + [DataField] public string? SplatPrototype { get; set; } #endregion + /// + /// The mutation effects that have been applied to this plant. + /// + [DataField] public List Mutations { get; set; } = new(); + /// /// The seed prototypes this seed may mutate into when prompted to. /// - [DataField("mutationPrototypes", customTypeSerializer: typeof(PrototypeIdListSerializer))] + [DataField(customTypeSerializer: typeof(PrototypeIdListSerializer))] public List MutationPrototypes = new(); public SeedData Clone() @@ -295,17 +284,14 @@ public SeedData Clone() Seedless = Seedless, Viable = Viable, - Slip = Slip, - Sentient = Sentient, Ligneous = Ligneous, PlantRsi = PlantRsi, PlantIconState = PlantIconState, - Bioluminescent = Bioluminescent, CanScream = CanScream, TurnIntoKudzu = TurnIntoKudzu, - BioluminescentColor = BioluminescentColor, SplatPrototype = SplatPrototype, + Mutations = Mutations, // Newly cloned seed is unique. No need to unnecessarily clone if repeatedly modified. Unique = true, @@ -356,18 +342,16 @@ public SeedData SpeciesChange(SeedData other) HarvestRepeat = HarvestRepeat, Potency = Potency, + Mutations = Mutations, + Seedless = Seedless, Viable = Viable, - Slip = Slip, - Sentient = Sentient, Ligneous = Ligneous, PlantRsi = other.PlantRsi, PlantIconState = other.PlantIconState, - Bioluminescent = Bioluminescent, CanScream = CanScream, TurnIntoKudzu = TurnIntoKudzu, - BioluminescentColor = BioluminescentColor, SplatPrototype = other.SplatPrototype, // Newly cloned seed is unique. No need to unnecessarily clone if repeatedly modified. diff --git a/Content.Server/Botany/Systems/BotanySystem.Produce.cs b/Content.Server/Botany/Systems/BotanySystem.Produce.cs index 34559a8304f..8fdf96f57ba 100644 --- a/Content.Server/Botany/Systems/BotanySystem.Produce.cs +++ b/Content.Server/Botany/Systems/BotanySystem.Produce.cs @@ -1,4 +1,5 @@ using Content.Server.Botany.Components; +using Content.Shared.EntityEffects; using Content.Shared.FixedPoint; namespace Content.Server.Botany.Systems; @@ -10,6 +11,15 @@ public void ProduceGrown(EntityUid uid, ProduceComponent produce) if (!TryGetSeed(produce, out var seed)) return; + foreach (var mutation in seed.Mutations) + { + if (mutation.AppliesToProduce) + { + var args = new EntityEffectBaseArgs(uid, EntityManager); + mutation.Effect.Effect(args); + } + } + if (!_solutionContainerSystem.EnsureSolution(uid, produce.SolutionName, out var solutionContainer, diff --git a/Content.Server/Botany/Systems/BotanySystem.Seed.cs b/Content.Server/Botany/Systems/BotanySystem.Seed.cs index c988e5338c0..1487ed71d47 100644 --- a/Content.Server/Botany/Systems/BotanySystem.Seed.cs +++ b/Content.Server/Botany/Systems/BotanySystem.Seed.cs @@ -5,16 +5,11 @@ using Content.Shared.Botany; using Content.Shared.Examine; using Content.Shared.Hands.EntitySystems; -using Content.Shared.Physics; using Content.Shared.Popups; using Content.Shared.Random; using Content.Shared.Random.Helpers; -using Content.Shared.Slippery; -using Content.Shared.StepTrigger.Components; using Robust.Server.GameObjects; using Robust.Shared.Map; -using Robust.Shared.Physics; -using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Systems; using Robust.Shared.Prototypes; using Robust.Shared.Random; @@ -34,7 +29,6 @@ public sealed partial class BotanySystem : EntitySystem [Dependency] private readonly SharedSolutionContainerSystem _solutionContainerSystem = default!; [Dependency] private readonly MetaDataSystem _metaData = default!; [Dependency] private readonly FixtureSystem _fixtureSystem = default!; - [Dependency] private readonly CollisionWakeSystem _colWakeSystem = default!; [Dependency] private readonly RandomHelperSystem _randomHelper = default!; public override void Initialize() @@ -183,30 +177,6 @@ public IEnumerable GenerateProduct(SeedData proto, EntityCoordinates _metaData.SetEntityDescription(entity, metaData.EntityDescription + " " + Loc.GetString("botany-mysterious-description-addon"), metaData); } - - if (proto.Bioluminescent) - { - var light = _light.EnsureLight(entity); - _light.SetRadius(entity, proto.BioluminescentRadius, light); - _light.SetColor(entity, proto.BioluminescentColor, light); - // TODO: Ayo why you copy-pasting code between here and plantholder? - _light.SetCastShadows(entity, false, light); // this is expensive, and botanists make lots of plants - } - - if (proto.Slip) - { - var slippery = EnsureComp(entity); - Dirty(entity, slippery); - EnsureComp(entity); - // Need a fixture with a slip layer in order to actually do the slipping - var fixtures = EnsureComp(entity); - var body = EnsureComp(entity); - var shape = fixtures.Fixtures["fix1"].Shape; - _fixtureSystem.TryCreateFixture(entity, shape, "slips", 1, false, (int) CollisionGroup.SlipLayer, manager: fixtures, body: body); - // Need to disable collision wake so that mobs can collide with and slip on it - var collisionWake = EnsureComp(entity); - _colWakeSystem.SetEnabled(entity, false, collisionWake); - } } return products; diff --git a/Content.Server/Botany/Systems/MutationSystem.cs b/Content.Server/Botany/Systems/MutationSystem.cs index d3159655f54..07a24d19f6b 100644 --- a/Content.Server/Botany/Systems/MutationSystem.cs +++ b/Content.Server/Botany/Systems/MutationSystem.cs @@ -1,9 +1,9 @@ +using Content.Shared.Atmos; +using Content.Shared.EntityEffects; +using Content.Shared.Random; using Robust.Shared.Prototypes; using Robust.Shared.Random; -using Content.Shared.Random; -using Content.Shared.Random.Helpers; using System.Linq; -using Content.Shared.Atmos; namespace Content.Server.Botany; @@ -11,25 +11,40 @@ public sealed class MutationSystem : EntitySystem { [Dependency] private readonly IRobustRandom _robustRandom = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - private WeightedRandomFillSolutionPrototype _randomChems = default!; - + private RandomPlantMutationListPrototype _randomMutations = default!; public override void Initialize() { - _randomChems = _prototypeManager.Index("RandomPickBotanyReagent"); + _randomMutations = _prototypeManager.Index("RandomPlantMutations"); + } + + /// + /// For each random mutation, see if it occurs on this plant this check. + /// + /// + /// + public void CheckRandomMutations(EntityUid plantHolder, ref SeedData seed, float severity) + { + foreach (var mutation in _randomMutations.mutations) + { + if (Random(mutation.BaseOdds * severity)) + { + if (mutation.AppliesToPlant) + { + var args = new EntityEffectBaseArgs(plantHolder, EntityManager); + mutation.Effect.Effect(args); + } + // Stat adjustments do not persist by being an attached effect, they just change the stat. + if (mutation.Persists && !seed.Mutations.Any(m => m.Name == mutation.Name)) + seed.Mutations.Add(mutation); + } + } } /// - /// Main idea: Simulate genetic mutation using random binary flips. Each - /// seed attribute can be encoded with a variable number of bits, e.g. - /// NutrientConsumption is represented by 5 bits randomly distributed in the - /// plant's genome which thermometer code the floating value between 0.1 and - /// 5. 1 unit of mutation flips one bit in the plant's genome, which changes - /// NutrientConsumption if one of those 5 bits gets affected. - /// - /// You MUST clone() seed before mutating it! + /// Checks all defined mutations against a seed to see which of them are applied. /// - public void MutateSeed(ref SeedData seed, float severity) + public void MutateSeed(EntityUid plantHolder, ref SeedData seed, float severity) { if (!seed.Unique) { @@ -37,57 +52,7 @@ public void MutateSeed(ref SeedData seed, float severity) return; } - // Add up everything in the bits column and put the number here. - const int totalbits = 262; - - #pragma warning disable IDE0055 // disable formatting warnings because this looks more readable - // Tolerances (55) - MutateFloat(ref seed.NutrientConsumption , 0.05f, 1.2f, 5, totalbits, severity); - MutateFloat(ref seed.WaterConsumption , 3f , 9f , 5, totalbits, severity); - MutateFloat(ref seed.IdealHeat , 263f , 323f, 5, totalbits, severity); - MutateFloat(ref seed.HeatTolerance , 2f , 25f , 5, totalbits, severity); - MutateFloat(ref seed.IdealLight , 0f , 14f , 5, totalbits, severity); - MutateFloat(ref seed.LightTolerance , 1f , 5f , 5, totalbits, severity); - MutateFloat(ref seed.ToxinsTolerance , 1f , 10f , 5, totalbits, severity); - MutateFloat(ref seed.LowPressureTolerance , 60f , 100f, 5, totalbits, severity); - MutateFloat(ref seed.HighPressureTolerance, 100f , 140f, 5, totalbits, severity); - MutateFloat(ref seed.PestTolerance , 0f , 15f , 5, totalbits, severity); - MutateFloat(ref seed.WeedTolerance , 0f , 15f , 5, totalbits, severity); - - // Stats (30*2 = 60) - MutateFloat(ref seed.Endurance , 50f , 150f, 5, totalbits, 2 * severity); - MutateInt(ref seed.Yield , 3 , 10 , 5, totalbits, 2 * severity); - MutateFloat(ref seed.Lifespan , 10f , 80f , 5, totalbits, 2 * severity); - MutateFloat(ref seed.Maturation , 3f , 8f , 5, totalbits, 2 * severity); - MutateFloat(ref seed.Production , 1f , 10f , 5, totalbits, 2 * severity); - MutateFloat(ref seed.Potency , 30f , 100f, 5, totalbits, 2 * severity); - - // Kill the plant (30) - MutateBool(ref seed.Viable , false, 30, totalbits, severity); - - // Fun (72) - MutateBool(ref seed.Seedless , true , 10, totalbits, severity); - MutateBool(ref seed.Slip , true , 10, totalbits, severity); - MutateBool(ref seed.Sentient , true , 2 , totalbits, severity); - MutateBool(ref seed.Ligneous , true , 10, totalbits, severity); - MutateBool(ref seed.Bioluminescent, true , 10, totalbits, severity); - MutateBool(ref seed.TurnIntoKudzu , true , 10, totalbits, severity); - MutateBool(ref seed.CanScream , true , 10, totalbits, severity); - seed.BioluminescentColor = RandomColor(seed.BioluminescentColor, 10, totalbits, severity); - #pragma warning restore IDE0055 - - // ConstantUpgade (10) - MutateHarvestType(ref seed.HarvestRepeat, 10, totalbits, severity); - - // Gas (5) - MutateGasses(ref seed.ExudeGasses, 0.01f, 0.5f, 4, totalbits, severity); - MutateGasses(ref seed.ConsumeGasses, 0.01f, 0.5f, 1, totalbits, severity); - - // Chems (20) - MutateChemicals(ref seed.Chemicals, 20, totalbits, severity); - - // Species (10) - MutateSpecies(ref seed, 10, totalbits, severity); + CheckRandomMutations(plantHolder, ref seed, severity); } public SeedData Cross(SeedData a, SeedData b) @@ -115,19 +80,18 @@ public SeedData Cross(SeedData a, SeedData b) CrossFloat(ref result.Production, a.Production); CrossFloat(ref result.Potency, a.Potency); - // we do not transfer Sentient to another plant to avoid ghost role spam CrossBool(ref result.Seedless, a.Seedless); - CrossBool(ref result.Viable, a.Viable); - CrossBool(ref result.Slip, a.Slip); CrossBool(ref result.Ligneous, a.Ligneous); - CrossBool(ref result.Bioluminescent, a.Bioluminescent); CrossBool(ref result.TurnIntoKudzu, a.TurnIntoKudzu); CrossBool(ref result.CanScream, a.CanScream); CrossGasses(ref result.ExudeGasses, a.ExudeGasses); CrossGasses(ref result.ConsumeGasses, a.ConsumeGasses); - result.BioluminescentColor = Random(0.5f) ? a.BioluminescentColor : result.BioluminescentColor; + // LINQ Explanation + // For the list of mutation effects on both plants, use a 50% chance to pick each one. + // Union all of the chosen mutations into one list, and pick ones with a Distinct (unique) name. + result.Mutations = result.Mutations.Where(m => Random(0.5f)).Union(a.Mutations.Where(m => Random(0.5f))).DistinctBy(m => m.Name).ToList(); // Hybrids have a high chance of being seedless. Balances very // effective hybrid crossings. @@ -139,206 +103,6 @@ public SeedData Cross(SeedData a, SeedData b) return result; } - // Mutate reference 'val' between 'min' and 'max' by pretending the value - // is representable by a thermometer code with 'bits' number of bits and - // randomly flipping some of them. - // - // 'totalbits' and 'mult' are used only to calculate the probability that - // one bit gets flipped. - private void MutateFloat(ref float val, float min, float max, int bits, int totalbits, float mult) - { - // Probability that a bit flip happens for this value's representation in thermometer code. - float probBitflip = mult * bits / totalbits; - probBitflip = Math.Clamp(probBitflip, 0, 1); - if (!Random(probBitflip)) - return; - - if (min == max) - { - val = min; - return; - } - - // Starting number of bits that are high, between 0 and bits. - // In other words, it's val mapped linearly from range [min, max] to range [0, bits], and then rounded. - int valInt = (int)MathF.Round((val - min) / (max - min) * bits); - // val may be outside the range of min/max due to starting prototype values, so clamp. - valInt = Math.Clamp(valInt, 0, bits); - - // Probability that the bit flip increases n. - // The higher the current value is, the lower the probability of increasing value is, and the higher the probability of decreasive it it. - // In other words, it tends to go to the middle. - float probIncrease = 1 - (float)valInt / bits; - int valIntMutated; - if (Random(probIncrease)) - { - valIntMutated = valInt + 1; - } - else - { - valIntMutated = valInt - 1; - } - - // Set value based on mutated thermometer code. - float valMutated = Math.Clamp((float)valIntMutated / bits * (max - min) + min, min, max); - val = valMutated; - } - - private void MutateInt(ref int val, int min, int max, int bits, int totalbits, float mult) - { - // Probability that a bit flip happens for this value's representation in thermometer code. - float probBitflip = mult * bits / totalbits; - probBitflip = Math.Clamp(probBitflip, 0, 1); - if (!Random(probBitflip)) - return; - - if (min == max) - { - val = min; - return; - } - - // Starting number of bits that are high, between 0 and bits. - // In other words, it's val mapped linearly from range [min, max] to range [0, bits], and then rounded. - int valInt = (int)MathF.Round((val - min) / (max - min) * bits); - // val may be outside the range of min/max due to starting prototype values, so clamp. - valInt = Math.Clamp(valInt, 0, bits); - - // Probability that the bit flip increases n. - // The higher the current value is, the lower the probability of increasing value is, and the higher the probability of decreasing it. - // In other words, it tends to go to the middle. - float probIncrease = 1 - (float)valInt / bits; - int valMutated; - if (Random(probIncrease)) - { - valMutated = val + 1; - } - else - { - valMutated = val - 1; - } - - valMutated = Math.Clamp(valMutated, min, max); - val = valMutated; - } - - private void MutateBool(ref bool val, bool polarity, int bits, int totalbits, float mult) - { - // Probability that a bit flip happens for this value. - float probSet = mult * bits / totalbits; - probSet = Math.Clamp(probSet, 0, 1); - if (!Random(probSet)) - return; - - val = polarity; - } - - private void MutateHarvestType(ref HarvestType val, int bits, int totalbits, float mult) - { - float probModify = mult * bits / totalbits; - probModify = Math.Clamp(probModify, 0, 1); - - if (!Random(probModify)) - return; - - if (val == HarvestType.NoRepeat) - val = HarvestType.Repeat; - else if (val == HarvestType.Repeat) - val = HarvestType.SelfHarvest; - } - - private void MutateGasses(ref Dictionary gasses, float min, float max, int bits, int totalbits, float mult) - { - float probModify = mult * bits / totalbits; - probModify = Math.Clamp(probModify, 0, 1); - if (!Random(probModify)) - return; - - // Add a random amount of a random gas to this gas dictionary - float amount = _robustRandom.NextFloat(min, max); - Gas gas = _robustRandom.Pick(Enum.GetValues(typeof(Gas)).Cast().ToList()); - if (gasses.ContainsKey(gas)) - { - gasses[gas] += amount; - } - else - { - gasses.Add(gas, amount); - } - } - - private void MutateChemicals(ref Dictionary chemicals, int bits, int totalbits, float mult) - { - float probModify = mult * bits / totalbits; - probModify = Math.Clamp(probModify, 0, 1); - if (!Random(probModify)) - return; - - // Add a random amount of a random chemical to this set of chemicals - if (_randomChems != null) - { - var pick = _randomChems.Pick(_robustRandom); - string chemicalId = pick.reagent; - int amount = _robustRandom.Next(1, (int)pick.quantity); - SeedChemQuantity seedChemQuantity = new SeedChemQuantity(); - if (chemicals.ContainsKey(chemicalId)) - { - seedChemQuantity.Min = chemicals[chemicalId].Min; - seedChemQuantity.Max = chemicals[chemicalId].Max + amount; - } - else - { - seedChemQuantity.Min = 1; - seedChemQuantity.Max = 1 + amount; - seedChemQuantity.Inherent = false; - } - int potencyDivisor = (int)Math.Ceiling(100.0f / seedChemQuantity.Max); - seedChemQuantity.PotencyDivisor = potencyDivisor; - chemicals[chemicalId] = seedChemQuantity; - } - } - - private void MutateSpecies(ref SeedData seed, int bits, int totalbits, float mult) - { - float p = mult * bits / totalbits; - p = Math.Clamp(p, 0, 1); - if (!Random(p)) - return; - - if (seed.MutationPrototypes.Count == 0) - return; - - var targetProto = _robustRandom.Pick(seed.MutationPrototypes); - _prototypeManager.TryIndex(targetProto, out SeedPrototype? protoSeed); - - if (protoSeed == null) - { - Log.Error($"Seed prototype could not be found: {targetProto}!"); - return; - } - - seed = seed.SpeciesChange(protoSeed); - } - - private Color RandomColor(Color color, int bits, int totalbits, float mult) - { - float probModify = mult * bits / totalbits; - if (Random(probModify)) - { - var colors = new List{ - Color.White, - Color.Red, - Color.Yellow, - Color.Green, - Color.Blue, - Color.Purple, - Color.Pink - }; - return _robustRandom.Pick(colors); - } - return color; - } - private void CrossChemicals(ref Dictionary val, Dictionary other) { // Go through chemicals from the pollen in swab diff --git a/Content.Server/Botany/Systems/PlantHolderSystem.cs b/Content.Server/Botany/Systems/PlantHolderSystem.cs index 002a0543399..0fdca029b79 100644 --- a/Content.Server/Botany/Systems/PlantHolderSystem.cs +++ b/Content.Server/Botany/Systems/PlantHolderSystem.cs @@ -1,8 +1,6 @@ -using Content.Server.Atmos; using Content.Server.Atmos.EntitySystems; using Content.Server.Botany.Components; using Content.Server.Fluids.Components; -using Content.Server.Ghost.Roles.Components; using Content.Server.Kitchen.Components; using Content.Server.Popups; using Content.Shared.Chemistry.EntitySystems; @@ -79,7 +77,7 @@ private int GetCurrentGrowthStage(Entity entity) if (component.Seed == null) return 0; - var result = Math.Max(1, (int) (component.Age * component.Seed.GrowthStages / component.Seed.Maturation)); + var result = Math.Max(1, (int)(component.Age * component.Seed.GrowthStages / component.Seed.Maturation)); return result; } @@ -125,9 +123,9 @@ private void OnExamine(Entity entity, ref ExaminedEvent ar args.PushMarkup(Loc.GetString("plant-holder-component-pest-high-level-message")); args.PushMarkup(Loc.GetString($"plant-holder-component-water-level-message", - ("waterLevel", (int) component.WaterLevel))); + ("waterLevel", (int)component.WaterLevel))); args.PushMarkup(Loc.GetString($"plant-holder-component-nutrient-level-message", - ("nutritionLevel", (int) component.NutritionLevel))); + ("nutritionLevel", (int)component.NutritionLevel))); if (component.DrawWarnings) { @@ -299,21 +297,12 @@ private void OnInteractUsing(Entity entity, ref InteractUs healthOverride = component.Health; } var packetSeed = component.Seed; - if (packetSeed.Sentient) - { - packetSeed = packetSeed.Clone(); // clone before modifying the seed - packetSeed.Sentient = false; - } - else - { - packetSeed.Unique = false; - } var seed = _botany.SpawnSeedPacket(packetSeed, Transform(args.User).Coordinates, args.User, healthOverride); _randomHelper.RandomOffset(seed, 0.25f); var displayName = Loc.GetString(component.Seed.DisplayName); _popup.PopupCursor(Loc.GetString("plant-holder-component-take-sample-message", ("seedName", displayName)), args.User); - + DoScream(entity.Owner, component.Seed); if (_random.Prob(0.3f)) @@ -459,7 +448,7 @@ public void Update(EntityUid uid, PlantHolderComponent? component = null) else { if (_random.Prob(0.8f)) - component.Age += (int) (1 * HydroponicsSpeedMultiplier); + component.Age += (int)(1 * HydroponicsSpeedMultiplier); component.UpdateSpriteAfterUpdate = true; } @@ -632,12 +621,6 @@ public void Update(EntityUid uid, PlantHolderComponent? component = null) else if (component.Age < 0) // Revert back to seed packet! { var packetSeed = component.Seed; - if (packetSeed.Sentient) - { - if (!packetSeed.Unique) // clone if necessary before modifying the seed - packetSeed = packetSeed.Clone(); - packetSeed.Sentient = false; // remove Sentient to avoid ghost role spam - } // will put it in the trays hands if it has any, please do not try doing this _botany.SpawnSeedPacket(packetSeed, Transform(uid).Coordinates, uid); RemovePlant(uid, component); @@ -674,14 +657,6 @@ public void Update(EntityUid uid, PlantHolderComponent? component = null) CheckLevelSanity(uid, component); - if (component.Seed.Sentient) - { - var ghostRole = EnsureComp(uid); - EnsureComp(uid); - ghostRole.RoleName = MetaData(uid).EntityName; - ghostRole.RoleDescription = Loc.GetString("station-event-random-sentience-role-description", ("name", ghostRole.RoleName)); - } - if (component.UpdateSpriteAfterUpdate) UpdateSprite(uid, component); } @@ -911,7 +886,7 @@ private void Mutate(EntityUid uid, float severity, PlantHolderComponent? compone if (component.Seed != null) { EnsureUniqueSeed(uid, component); - _mutation.MutateSeed(ref component.Seed, severity); + _mutation.MutateSeed(uid, ref component.Seed, severity); } } @@ -922,19 +897,6 @@ public void UpdateSprite(EntityUid uid, PlantHolderComponent? component = null) component.UpdateSpriteAfterUpdate = false; - if (component.Seed != null && component.Seed.Bioluminescent) - { - var light = EnsureComp(uid); - _pointLight.SetRadius(uid, component.Seed.BioluminescentRadius, light); - _pointLight.SetColor(uid, component.Seed.BioluminescentColor, light); - _pointLight.SetCastShadows(uid, false, light); - Dirty(uid, light); - } - else - { - RemComp(uid); - } - if (!TryComp(uid, out var app)) return; diff --git a/Content.Server/Botany/Systems/SeedExtractorSystem.cs b/Content.Server/Botany/Systems/SeedExtractorSystem.cs index 4a0d56bfe98..93f76473ff8 100644 --- a/Content.Server/Botany/Systems/SeedExtractorSystem.cs +++ b/Content.Server/Botany/Systems/SeedExtractorSystem.cs @@ -43,12 +43,6 @@ private void OnInteractUsing(EntityUid uid, SeedExtractorComponent seedExtractor var coords = Transform(uid).Coordinates; var packetSeed = seed; - if (packetSeed.Sentient) - { - if (!packetSeed.Unique) // clone if necessary before modifying the seed - packetSeed = packetSeed.Clone(); - packetSeed.Sentient = false; // remove Sentient to avoid ghost role spam - } if (amount > 1) packetSeed.Unique = false; diff --git a/Content.Server/EntityEffects/Effects/Glow.cs b/Content.Server/EntityEffects/Effects/Glow.cs new file mode 100644 index 00000000000..9f034767297 --- /dev/null +++ b/Content.Server/EntityEffects/Effects/Glow.cs @@ -0,0 +1,48 @@ +using Content.Shared.EntityEffects; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; + +namespace Content.Server.EntityEffects.Effects; + +/// +/// Makes a mob glow. +/// +public sealed partial class Glow : EntityEffect +{ + [DataField] + public float Radius = 2f; + + [DataField] + public Color Color = Color.Black; + + private static readonly List Colors = new() + { + Color.White, + Color.Red, + Color.Yellow, + Color.Green, + Color.Blue, + Color.Purple, + Color.Pink + }; + + public override void Effect(EntityEffectBaseArgs args) + { + if (Color == Color.Black) + { + var random = IoCManager.Resolve(); + Color = random.Pick(Colors); + } + + var lightSystem = args.EntityManager.System(); + var light = lightSystem.EnsureLight(args.TargetEntity); + lightSystem.SetRadius(args.TargetEntity, Radius, light); + lightSystem.SetColor(args.TargetEntity, Color, light); + lightSystem.SetCastShadows(args.TargetEntity, false, light); // this is expensive, and botanists make lots of plants + } + + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + { + return "TODO"; + } +} diff --git a/Content.Server/EntityEffects/Effects/PlantChangeStat.cs b/Content.Server/EntityEffects/Effects/PlantChangeStat.cs new file mode 100644 index 00000000000..9592ff779da --- /dev/null +++ b/Content.Server/EntityEffects/Effects/PlantChangeStat.cs @@ -0,0 +1,142 @@ +using Content.Server.Botany; +using Content.Server.Botany.Components; +using Content.Shared.EntityEffects; +using JetBrains.Annotations; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; + +namespace Content.Server.EntityEffects.Effects.PlantMetabolism; + +[UsedImplicitly] +public sealed partial class PlantChangeStat : EntityEffect +{ + [DataField] + public string TargetValue; + + [DataField] + public float MinValue; + + [DataField] + public float MaxValue; + + [DataField] + public int Steps; + + public override void Effect(EntityEffectBaseArgs args) + { + var plantHolder = args.EntityManager.GetComponent(args.TargetEntity); + if (plantHolder == null || plantHolder.Seed == null) + return; + + var member = plantHolder.Seed.GetType().GetField(TargetValue); + var mutationSys = args.EntityManager.System(); + + if (member == null) + { + mutationSys.Log.Error(this.GetType().Name + " Error: Member " + TargetValue + " not found on " + plantHolder.GetType().Name + ". Did you misspell it?"); + return; + } + + var currentValObj = member.GetValue(plantHolder.Seed); + if (currentValObj == null) + return; + + if (member.FieldType == typeof(float)) + { + var floatVal = (float)currentValObj; + MutateFloat(ref floatVal, MinValue, MaxValue, Steps); + member.SetValue(plantHolder.Seed, floatVal); + } + else if (member.FieldType == typeof(int)) + { + var intVal = (int)currentValObj; + MutateInt(ref intVal, (int)MinValue, (int)MaxValue, Steps); + member.SetValue(plantHolder.Seed, intVal); + } + else if (member.FieldType == typeof(bool)) + { + var boolVal = (bool)currentValObj; + boolVal = !boolVal; + member.SetValue(plantHolder.Seed, boolVal); + } + } + + // Mutate reference 'val' between 'min' and 'max' by pretending the value + // is representable by a thermometer code with 'bits' number of bits and + // randomly flipping some of them. + private void MutateFloat(ref float val, float min, float max, int bits) + { + if (min == max) + { + val = min; + return; + } + + // Starting number of bits that are high, between 0 and bits. + // In other words, it's val mapped linearly from range [min, max] to range [0, bits], and then rounded. + int valInt = (int)MathF.Round((val - min) / (max - min) * bits); + // val may be outside the range of min/max due to starting prototype values, so clamp. + valInt = Math.Clamp(valInt, 0, bits); + + // Probability that the bit flip increases n. + // The higher the current value is, the lower the probability of increasing value is, and the higher the probability of decreasive it it. + // In other words, it tends to go to the middle. + float probIncrease = 1 - (float)valInt / bits; + int valIntMutated; + if (Random(probIncrease)) + { + valIntMutated = valInt + 1; + } + else + { + valIntMutated = valInt - 1; + } + + // Set value based on mutated thermometer code. + float valMutated = Math.Clamp((float)valIntMutated / bits * (max - min) + min, min, max); + val = valMutated; + } + + private void MutateInt(ref int val, int min, int max, int bits) + { + if (min == max) + { + val = min; + return; + } + + // Starting number of bits that are high, between 0 and bits. + // In other words, it's val mapped linearly from range [min, max] to range [0, bits], and then rounded. + int valInt = (int)MathF.Round((val - min) / (max - min) * bits); + // val may be outside the range of min/max due to starting prototype values, so clamp. + valInt = Math.Clamp(valInt, 0, bits); + + // Probability that the bit flip increases n. + // The higher the current value is, the lower the probability of increasing value is, and the higher the probability of decreasing it. + // In other words, it tends to go to the middle. + float probIncrease = 1 - (float)valInt / bits; + int valMutated; + if (Random(probIncrease)) + { + valMutated = val + 1; + } + else + { + valMutated = val - 1; + } + + valMutated = Math.Clamp(valMutated, min, max); + val = valMutated; + } + + private bool Random(float odds) + { + var random = IoCManager.Resolve(); + return random.Prob(odds); + } + + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + { + throw new NotImplementedException(); + } +} diff --git a/Content.Server/EntityEffects/Effects/PlantMutateChemicals.cs b/Content.Server/EntityEffects/Effects/PlantMutateChemicals.cs new file mode 100644 index 00000000000..7ee6cd13d75 --- /dev/null +++ b/Content.Server/EntityEffects/Effects/PlantMutateChemicals.cs @@ -0,0 +1,55 @@ +using Content.Server.Botany; +using Content.Server.Botany.Components; +using Content.Shared.EntityEffects; +using Content.Shared.Random; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; + +namespace Content.Server.EntityEffects.Effects; + +/// +/// changes the chemicals available in a plant's produce +/// +public sealed partial class PlantMutateChemicals : EntityEffect +{ + public override void Effect(EntityEffectBaseArgs args) + { + var plantholder = args.EntityManager.GetComponent(args.TargetEntity); + + if (plantholder.Seed == null) + return; + + var random = IoCManager.Resolve(); + var prototypeManager = IoCManager.Resolve(); + var chemicals = plantholder.Seed.Chemicals; + var randomChems = prototypeManager.Index("RandomPickBotanyReagent").Fills; + + // Add a random amount of a random chemical to this set of chemicals + if (randomChems != null) + { + var pick = random.Pick(randomChems); + var chemicalId = random.Pick(pick.Reagents); + var amount = random.Next(1, (int)pick.Quantity); + var seedChemQuantity = new SeedChemQuantity(); + if (chemicals.ContainsKey(chemicalId)) + { + seedChemQuantity.Min = chemicals[chemicalId].Min; + seedChemQuantity.Max = chemicals[chemicalId].Max + amount; + } + else + { + seedChemQuantity.Min = 1; + seedChemQuantity.Max = 1 + amount; + seedChemQuantity.Inherent = false; + } + var potencyDivisor = (int)Math.Ceiling(100.0f / seedChemQuantity.Max); + seedChemQuantity.PotencyDivisor = potencyDivisor; + chemicals[chemicalId] = seedChemQuantity; + } + } + + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + { + return "TODO"; + } +} diff --git a/Content.Server/EntityEffects/Effects/PlantMutateGases.cs b/Content.Server/EntityEffects/Effects/PlantMutateGases.cs new file mode 100644 index 00000000000..52b9da3a851 --- /dev/null +++ b/Content.Server/EntityEffects/Effects/PlantMutateGases.cs @@ -0,0 +1,87 @@ +using Content.Server.Botany.Components; +using Content.Shared.Atmos; +using Content.Shared.EntityEffects; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; +using System.Linq; + +namespace Content.Server.EntityEffects.Effects; + +/// +/// changes the gases that a plant or produce create. +/// +public sealed partial class PlantMutateExudeGasses : EntityEffect +{ + [DataField] + public float MinValue = 0.01f; + + [DataField] + public float MaxValue = 0.5f; + + public override void Effect(EntityEffectBaseArgs args) + { + var plantholder = args.EntityManager.GetComponent(args.TargetEntity); + + if (plantholder.Seed == null) + return; + + var random = IoCManager.Resolve(); + var gasses = plantholder.Seed.ExudeGasses; + + // Add a random amount of a random gas to this gas dictionary + float amount = random.NextFloat(MinValue, MaxValue); + Gas gas = random.Pick(Enum.GetValues(typeof(Gas)).Cast().ToList()); + if (gasses.ContainsKey(gas)) + { + gasses[gas] += amount; + } + else + { + gasses.Add(gas, amount); + } + } + + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + { + return "TODO"; + } +} + +/// +/// changes the gases that a plant or produce consumes. +/// +public sealed partial class PlantMutateConsumeGasses : EntityEffect +{ + [DataField] + public float MinValue = 0.01f; + + [DataField] + public float MaxValue = 0.5f; + public override void Effect(EntityEffectBaseArgs args) + { + var plantholder = args.EntityManager.GetComponent(args.TargetEntity); + + if (plantholder.Seed == null) + return; + + var random = IoCManager.Resolve(); + var gasses = plantholder.Seed.ConsumeGasses; + + // Add a random amount of a random gas to this gas dictionary + float amount = random.NextFloat(MinValue, MaxValue); + Gas gas = random.Pick(Enum.GetValues(typeof(Gas)).Cast().ToList()); + if (gasses.ContainsKey(gas)) + { + gasses[gas] += amount; + } + else + { + gasses.Add(gas, amount); + } + } + + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + { + return "TODO"; + } +} diff --git a/Content.Server/EntityEffects/Effects/PlantMutateHarvest.cs b/Content.Server/EntityEffects/Effects/PlantMutateHarvest.cs new file mode 100644 index 00000000000..e67176ee16d --- /dev/null +++ b/Content.Server/EntityEffects/Effects/PlantMutateHarvest.cs @@ -0,0 +1,30 @@ +using Content.Server.Botany; +using Content.Server.Botany.Components; +using Content.Shared.EntityEffects; +using Robust.Shared.Prototypes; + +namespace Content.Server.EntityEffects.Effects; + +/// +/// Upgrades a plant's harvest type. +/// +public sealed partial class PlantMutateHarvest : EntityEffect +{ + public override void Effect(EntityEffectBaseArgs args) + { + var plantholder = args.EntityManager.GetComponent(args.TargetEntity); + + if (plantholder.Seed == null) + return; + + if (plantholder.Seed.HarvestRepeat == HarvestType.NoRepeat) + plantholder.Seed.HarvestRepeat = HarvestType.Repeat; + else if (plantholder.Seed.HarvestRepeat == HarvestType.Repeat) + plantholder.Seed.HarvestRepeat = HarvestType.SelfHarvest; + } + + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + { + return "TODO"; + } +} diff --git a/Content.Server/EntityEffects/Effects/PlantSpeciesChange.cs b/Content.Server/EntityEffects/Effects/PlantSpeciesChange.cs new file mode 100644 index 00000000000..65bd59daa37 --- /dev/null +++ b/Content.Server/EntityEffects/Effects/PlantSpeciesChange.cs @@ -0,0 +1,43 @@ +using Content.Server.Botany; +using Content.Server.Botany.Components; +using Content.Shared.EntityEffects; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; +using Serilog; + +namespace Content.Server.EntityEffects.Effects; + +/// +/// Changes a plant into one of the species its able to mutate into. +/// +public sealed partial class PlantSpeciesChange : EntityEffect +{ + public override void Effect(EntityEffectBaseArgs args) + { + var prototypeManager = IoCManager.Resolve(); + var plantholder = args.EntityManager.GetComponent(args.TargetEntity); + + if (plantholder.Seed == null) + return; + + if (plantholder.Seed.MutationPrototypes.Count == 0) + return; + + var random = IoCManager.Resolve(); + var targetProto = random.Pick(plantholder.Seed.MutationPrototypes); + prototypeManager.TryIndex(targetProto, out SeedPrototype? protoSeed); + + if (protoSeed == null) + { + Log.Error($"Seed prototype could not be found: {targetProto}!"); + return; + } + + plantholder.Seed = plantholder.Seed.SpeciesChange(protoSeed); + } + + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + { + return "TODO"; + } +} diff --git a/Content.Server/EntityEffects/Effects/Slipify.cs b/Content.Server/EntityEffects/Effects/Slipify.cs new file mode 100644 index 00000000000..bc1cc062a38 --- /dev/null +++ b/Content.Server/EntityEffects/Effects/Slipify.cs @@ -0,0 +1,38 @@ +using Content.Shared.EntityEffects; +using Content.Shared.Physics; +using Content.Shared.Slippery; +using Content.Shared.StepTrigger.Components; +using Robust.Shared.Physics; +using Robust.Shared.Physics.Components; +using Robust.Shared.Physics.Systems; +using Robust.Shared.Prototypes; + +namespace Content.Server.EntityEffects.Effects; + +/// +/// Makes a mob slippery. +/// +public sealed partial class Slipify : EntityEffect +{ + public override void Effect(EntityEffectBaseArgs args) + { + var fixtureSystem = args.EntityManager.System(); + var colWakeSystem = args.EntityManager.System(); + var slippery = args.EntityManager.EnsureComponent(args.TargetEntity); + args.EntityManager.Dirty(args.TargetEntity, slippery); + args.EntityManager.EnsureComponent(args.TargetEntity); + // Need a fixture with a slip layer in order to actually do the slipping + var fixtures = args.EntityManager.EnsureComponent(args.TargetEntity); + var body = args.EntityManager.EnsureComponent(args.TargetEntity); + var shape = fixtures.Fixtures["fix1"].Shape; + fixtureSystem.TryCreateFixture(args.TargetEntity, shape, "slips", 1, false, (int)CollisionGroup.SlipLayer, manager: fixtures, body: body); + // Need to disable collision wake so that mobs can collide with and slip on it + var collisionWake = args.EntityManager.EnsureComponent(args.TargetEntity); + colWakeSystem.SetEnabled(args.TargetEntity, false, collisionWake); + } + + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + { + throw new NotImplementedException(); + } +} diff --git a/Content.Shared/Random/RandomPlantMutation.cs b/Content.Shared/Random/RandomPlantMutation.cs new file mode 100644 index 00000000000..d95cf7bf422 --- /dev/null +++ b/Content.Shared/Random/RandomPlantMutation.cs @@ -0,0 +1,48 @@ +using Content.Shared.EntityEffects; +using Robust.Shared.Serialization; + +namespace Content.Shared.Random; + +/// +/// Data that specifies the odds and effects of possible random plant mutations. +/// +[Serializable, NetSerializable] +[DataDefinition] +public sealed partial class RandomPlantMutation +{ + /// + /// Odds of this mutation occurring with 1 point of mutation severity on a plant. + /// + [DataField] + public float BaseOdds = 0; + + /// + /// The name of this mutation. + /// + [DataField] + public string Name = ""; + + /// + /// The actual EntityEffect to apply to the target + /// + [DataField] + public EntityEffect Effect = default!; + + /// + /// This mutation will target the harvested produce + /// + [DataField] + public bool AppliesToProduce = true; + + /// + /// This mutation will target the growing plant as soon as this mutation is applied. + /// + [DataField] + public bool AppliesToPlant = true; + + /// + /// This mutation stays on the plant and its produce. If false while AppliesToPlant is true, the effect will run when triggered. + /// + [DataField] + public bool Persists = true; +} diff --git a/Content.Shared/Random/RandomPlantMutationListPrototype.cs b/Content.Shared/Random/RandomPlantMutationListPrototype.cs new file mode 100644 index 00000000000..84e3b9256c3 --- /dev/null +++ b/Content.Shared/Random/RandomPlantMutationListPrototype.cs @@ -0,0 +1,18 @@ +using Robust.Shared.Prototypes; + +namespace Content.Shared.Random; + +/// +/// Random weighting dataset for solutions, able to specify reagents quantity. +/// +[Prototype("RandomPlantMutationList")] +public sealed partial class RandomPlantMutationListPrototype : IPrototype +{ + [IdDataField] public string ID { get; } = default!; + + /// + /// List of RandomFills that can be picked from. + /// + [DataField("mutations", required: true, serverOnly: true)] + public List mutations = new(); +} diff --git a/Resources/Prototypes/Hydroponics/mutations.yml b/Resources/Prototypes/Hydroponics/randomChemicals.yml similarity index 100% rename from Resources/Prototypes/Hydroponics/mutations.yml rename to Resources/Prototypes/Hydroponics/randomChemicals.yml diff --git a/Resources/Prototypes/Hydroponics/randomMutations.yml b/Resources/Prototypes/Hydroponics/randomMutations.yml new file mode 100644 index 00000000000..50f6845ec32 --- /dev/null +++ b/Resources/Prototypes/Hydroponics/randomMutations.yml @@ -0,0 +1,178 @@ +- type: RandomPlantMutationList + id: RandomPlantMutations + mutations: + - name: Bioluminescent + baseOdds: 0.036 + effect: !type:Glow + - name: Sentient + baseOdds: 0.0072 + appliesToPlant: false # makes the botany tray sentient if true + effect: !type:MakeSentient # existing effect. + - name: Slippery + baseOdds: 0.036 + effect: !type:Slipify + - name: ChangeSpecies + baseOdds: 0.036 + appliesToProduce: false + effect: !type:PlantSpeciesChange + - name: Unviable + baseOdds: 0.109 + persists: false + effect: !type:PlantChangeStat + targetValue: Viable + - name: ChangeWaterConsumption + baseOdds: 0.018 + persists: false + effect: !type:PlantChangeStat + targetValue: WaterConsumption + minValue: 0.3 + maxValue: 0.9 + steps: 5 + - name: ChangeNutrientConsumption + baseOdds: 0.018 + persists: false + effect: !type:PlantChangeStat + targetValue: NutrientConsumption + minValue: 0.05 + maxValue: 1.2 + steps: 5 + - name: ChangeIdealHeat + baseOdds: 0.018 + persists: false + effect: !type:PlantChangeStat + targetValue: IdealHeat + minValue: 263 + maxValue: 323 + steps: 5 + - name: ChangeHeatTolerance + baseOdds: 0.018 + persists: false + effect: !type:PlantChangeStat + targetValue: HeatTolerance + minValue: 2 + maxValue: 25 + steps: 5 + - name: ChangeToxinsTolerance + baseOdds: 0.018 + persists: false + effect: !type:PlantChangeStat + targetValue: ToxinsTolerance + minValue: 1 + maxValue: 10 + steps: 5 + - name: ChangeLowPressureTolerance + baseOdds: 0.018 + persists: false + effect: !type:PlantChangeStat + targetValue: LowPressureTolerance + minValue: 60 + maxValue: 100 + steps: 5 + - name: ChangeHighPressureTolerance + baseOdds: 0.018 + persists: false + effect: !type:PlantChangeStat + targetValue: HighPressureTolerance + minValue: 100 + maxValue: 140 + steps: 5 + - name: ChangePestTolerance + baseOdds: 0.018 + persists: false + effect: !type:PlantChangeStat + targetValue: PestTolerance + minValue: 0 + maxValue: 15 + steps: 5 + - name: ChangeWeedTolerance + baseOdds: 0.018 + persists: false + effect: !type:PlantChangeStat + targetValue: WeedTolerance + minValue: 0 + maxValue: 15 + steps: 5 + - name: ChangeEndurance + baseOdds: 0.036 + persists: false + effect: !type:PlantChangeStat + targetValue: Endurance + minValue: 50 + maxValue: 150 + steps: 5 + - name: ChangeYield + baseOdds: 0.036 + persists: false + effect: !type:PlantChangeStat + targetValue: Yield + minValue: 3 + maxValue: 10 + steps: 5 + - name: ChangeLifespan + baseOdds: 0.036 + persists: false + effect: !type:PlantChangeStat + targetValue: Lifespan + minValue: 10 + maxValue: 80 + steps: 5 + - name: ChangeMaturation + baseOdds: 0.036 + persists: false + effect: !type:PlantChangeStat + targetValue: Maturation + minValue: 3 + maxValue: 8 + steps: 5 + - name: ChangeProduction + baseOdds: 0.036 + persists: false + effect: !type:PlantChangeStat + targetValue: Production + minValue: 1 + maxValue: 10 + steps: 5 + - name: ChangePotency + baseOdds: 0.036 + persists: false + effect: !type:PlantChangeStat + targetValue: Potency + minValue: 30 + maxValue: 100 + steps: 5 + - name: ChangeSeedless + baseOdds: 0.036 + persists: false + effect: !type:PlantChangeStat + targetValue: Seedless + - name: ChangeLigneous + baseOdds: 0.036 + persists: false + effect: !type:PlantChangeStat + targetValue: Ligneous + - name: ChangeTurnIntoKudzu + baseOdds: 0.036 + persists: false + effect: !type:PlantChangeStat + targetValue: TurnIntoKudzu + - name: ChangeScreaming + baseOdds: 0.036 + persists: false + effect: !type:PlantChangeStat + targetValue: CanScream + - name: ChangeChemicals + baseOdds: 0.072 + persists: false + effect: !type:PlantMutateChemicals + - name: ChangeExudeGasses + baseOdds: 0.0145 + persists: false + effect: !type:PlantMutateExudeGasses + - name: ChangeConsumeGasses + baseOdds: 0.0036 + persists: false + effect: !type:PlantMutateConsumeGasses + - name: ChangeHarvest + baseOdds: 0.036 + persists: false + effect: !type:PlantMutateHarvest \ No newline at end of file From 540b1b15b1369251511682a47aee7506a53e66a9 Mon Sep 17 00:00:00 2001 From: Plykiya <58439124+Plykiya@users.noreply.github.com> Date: Sat, 14 Sep 2024 21:00:06 -0700 Subject: [PATCH 062/138] Fix build and lint (#32180) --- .../Piping/Binary/EntitySystems/GasPressurePumpSystem.cs | 2 +- .../Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs | 2 +- Resources/Prototypes/Entities/Mobs/NPCs/animals.yml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasPressurePumpSystem.cs b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasPressurePumpSystem.cs index 56359a85af5..abd34396a0c 100644 --- a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasPressurePumpSystem.cs +++ b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasPressurePumpSystem.cs @@ -2,7 +2,6 @@ using Content.Server.Atmos.EntitySystems; using Content.Server.Atmos.Piping.Binary.Components; using Content.Server.Atmos.Piping.Components; -using Content.Server.NodeContainer; using Content.Server.NodeContainer.EntitySystems; using Content.Server.NodeContainer.Nodes; using Content.Server.Power.Components; @@ -14,6 +13,7 @@ using Content.Shared.Examine; using Content.Shared.Interaction; using Content.Shared.Popups; +using Content.Shared.Power; using JetBrains.Annotations; using Robust.Server.GameObjects; using Robust.Shared.Player; diff --git a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs index d1127920514..9ddd7dce67d 100644 --- a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs +++ b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs @@ -6,7 +6,6 @@ using Content.Server.DeviceNetwork; using Content.Server.DeviceNetwork.Components; using Content.Server.DeviceNetwork.Systems; -using Content.Server.NodeContainer; using Content.Server.NodeContainer.EntitySystems; using Content.Server.NodeContainer.Nodes; using Content.Server.Power.Components; @@ -18,6 +17,7 @@ using Content.Shared.Examine; using Content.Shared.Interaction; using Content.Shared.Popups; +using Content.Shared.Power; using JetBrains.Annotations; using Robust.Server.GameObjects; using Robust.Shared.Player; diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml index c06b5aacea2..495f5345534 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml @@ -3136,7 +3136,7 @@ Alive: Base: ferret Critical: - Base: + Base: ferret_dead Dead: Base: ferret_dead - type: Butcherable @@ -3344,7 +3344,7 @@ Alive: Base: pig Critical: - Base: + Base: dead Dead: Base: dead - type: Butcherable From 02c766261763bd74294ee876969f0f958060fab6 Mon Sep 17 00:00:00 2001 From: deltanedas <39013340+deltanedas@users.noreply.github.com> Date: Sun, 15 Sep 2024 19:04:31 +0000 Subject: [PATCH 063/138] prevent using holo inside containers (#32068) Co-authored-by: deltanedas <@deltanedas:kde.org> --- Content.Server/Guardian/GuardianSystem.cs | 6 ++++++ Resources/Locale/en-US/guardian/guardian.ftl | 1 + 2 files changed, 7 insertions(+) diff --git a/Content.Server/Guardian/GuardianSystem.cs b/Content.Server/Guardian/GuardianSystem.cs index ae4d0ca2b8c..7a1b875756e 100644 --- a/Content.Server/Guardian/GuardianSystem.cs +++ b/Content.Server/Guardian/GuardianSystem.cs @@ -80,6 +80,12 @@ private void OnPerformAction(EntityUid uid, GuardianHostComponent component, Gua if (args.Handled) return; + if (_container.IsEntityInContainer(uid)) + { + _popupSystem.PopupEntity(Loc.GetString("guardian-inside-container"), uid, uid); + return; + } + if (component.HostedGuardian != null) ToggleGuardian(uid, component); diff --git a/Resources/Locale/en-US/guardian/guardian.ftl b/Resources/Locale/en-US/guardian/guardian.ftl index 9e0966630dd..141646087d3 100644 --- a/Resources/Locale/en-US/guardian/guardian.ftl +++ b/Resources/Locale/en-US/guardian/guardian.ftl @@ -10,6 +10,7 @@ guardian-activator-empty-examine = [color=#ba1919]The injector is spent.[/color] guardian-activator-invalid-target = Only humans can be injected! guardian-no-soul = Your guardian has no soul. guardian-available = Your guardian now has a soul. +guardian-inside-container = There's no room to release your guardian! ## Guardian entity specific From 12e2371c8d5bf3a4f0e5a28986981e00aa693ba0 Mon Sep 17 00:00:00 2001 From: PJBot Date: Sun, 15 Sep 2024 19:05:39 +0000 Subject: [PATCH 064/138] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 1c8aac9c76f..49567e0a71a 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Simyon - changes: - - message: Ratkings now require at least 30 players in order to spawn. - type: Tweak - id: 6878 - time: '2024-07-07T13:06:24.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29737 - author: EmoGarbage404 changes: - message: Intercoms now use encryption keys to determine what channels they can @@ -3918,3 +3911,10 @@ id: 7377 time: '2024-09-15T01:58:10.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/28995 +- author: deltanedas + changes: + - message: Holoparasites can no longer be summoned from inside containers. + type: Tweak + id: 7378 + time: '2024-09-15T19:04:32.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/32068 From 7fed39d511b91dd7f018d172654599c33403c22c Mon Sep 17 00:00:00 2001 From: lzk <124214523+lzk228@users.noreply.github.com> Date: Sun, 15 Sep 2024 21:49:05 +0200 Subject: [PATCH 065/138] localize skeleton accent (#32166) * localize skeleton accent * commit number 2 * remove that from this * this * babushka --- .../EntitySystems/SkeletonAccentSystem.cs | 27 ++-------------- Resources/Locale/en-US/accent/skeleton.ftl | 32 +++++++++++++++++++ .../Prototypes/Accents/word_replacements.yml | 19 +++++++++++ 3 files changed, 54 insertions(+), 24 deletions(-) create mode 100644 Resources/Locale/en-US/accent/skeleton.ftl diff --git a/Content.Server/Speech/EntitySystems/SkeletonAccentSystem.cs b/Content.Server/Speech/EntitySystems/SkeletonAccentSystem.cs index d143c25fdba..1b773f1a5ac 100644 --- a/Content.Server/Speech/EntitySystems/SkeletonAccentSystem.cs +++ b/Content.Server/Speech/EntitySystems/SkeletonAccentSystem.cs @@ -7,29 +7,11 @@ namespace Content.Server.Speech.EntitySystems; public sealed partial class SkeletonAccentSystem : EntitySystem { [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly ReplacementAccentSystem _replacement = default!; [GeneratedRegex(@"(? DirectReplacements = new() - { - { "fuck you", "I've got a BONE to pick with you" }, - { "fucked", "boned"}, - { "fuck", "RATTLE RATTLE" }, - { "fck", "RATTLE RATTLE" }, - { "shit", "RATTLE RATTLE" }, // Capitalize RATTLE RATTLE regardless of original message case. - { "definitely", "make no bones about it" }, - { "absolutely", "make no bones about it" }, - { "afraid", "rattled"}, - { "scared", "rattled"}, - { "spooked", "rattled"}, - { "shocked", "rattled"}, - { "killed", "skeletonized"}, - { "humorous", "humerus"}, - { "to be a", "tibia"}, - { "under", "ulna"} - }; - public override void Initialize() { base.Initialize(); @@ -50,11 +32,8 @@ public string Accentuate(string message, SkeletonAccentComponent component) // At the start of words, any non-vowel + "one" becomes "bone", e.g. tone -> bone ; lonely -> bonely; clone -> clone (remains unchanged). msg = BoneRegex().Replace(msg, "bone"); - // Direct word/phrase replacements: - foreach (var (first, replace) in DirectReplacements) - { - msg = Regex.Replace(msg, $@"(? Date: Sun, 15 Sep 2024 22:03:15 +0200 Subject: [PATCH 066/138] French and Spanish traits (#30966) * Traits languages * Update traits.ftl Silly thing * No russian --------- Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com> --- Resources/Locale/en-US/traits/traits.ftl | 6 ++++++ Resources/Prototypes/Traits/speech.yml | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/Resources/Locale/en-US/traits/traits.ftl b/Resources/Locale/en-US/traits/traits.ftl index 8e3b1892161..7f4dcfe2eca 100644 --- a/Resources/Locale/en-US/traits/traits.ftl +++ b/Resources/Locale/en-US/traits/traits.ftl @@ -53,3 +53,9 @@ trait-german-desc = You seem to come from space Germany. trait-italian-name = Italian accent trait-italian-desc = Mamma mia! You seem to have lived in space Italy! + +trait-french-name = French accent +trait-french-desc = Your accent seems to have a certain «je ne sais quoi». + +trait-spanish-name = Spanish accent +trait-spanish-desc = Hola señor, donde esta la biblioteca. diff --git a/Resources/Prototypes/Traits/speech.yml b/Resources/Prototypes/Traits/speech.yml index e5869a4afc4..98d0368ed6e 100644 --- a/Resources/Prototypes/Traits/speech.yml +++ b/Resources/Prototypes/Traits/speech.yml @@ -63,6 +63,24 @@ - type: ReplacementAccent accent: italian +- type: trait + id: FrenchAccent + name: trait-french-name + description: trait-french-desc + category: SpeechTraits + cost: 1 + components: + - type: FrenchAccent + +- type: trait + id: SpanishAccent + name: trait-spanish-name + description: trait-spanish-desc + category: SpeechTraits + cost: 1 + components: + - type: SpanishAccent + - type: trait id: Liar name: trait-liar-name From 117a923c4aec3f7403bc1046b521d699a4fcd52d Mon Sep 17 00:00:00 2001 From: PJBot Date: Sun, 15 Sep 2024 20:04:22 +0000 Subject: [PATCH 067/138] Automatic changelog update --- Resources/Changelog/Changelog.yml | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 49567e0a71a..67d5e36fc3e 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,14 +1,4 @@ Entries: -- author: EmoGarbage404 - changes: - - message: Intercoms now use encryption keys to determine what channels they can - broadcast on. - type: Tweak - - message: Intercoms and handheld radios no longer rely on telecom servers. - type: Fix - id: 6879 - time: '2024-07-07T14:19:10.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29580 - author: Vermidia changes: - message: Some drink reactions now require shaking with the shaker or stirring @@ -3918,3 +3908,10 @@ id: 7378 time: '2024-09-15T19:04:32.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/32068 +- author: BackeTako + changes: + - message: Added French and Spanish speech traits. + type: Add + id: 7379 + time: '2024-09-15T20:03:15.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/30966 From 096ab07bf18d0209c55312faf68ebeafd898dac0 Mon Sep 17 00:00:00 2001 From: Plykiya <58439124+Plykiya@users.noreply.github.com> Date: Sun, 15 Sep 2024 13:04:37 -0700 Subject: [PATCH 068/138] Nerfs meteor penetration force (#32109) nerf meteor penetration force --- .../Entities/Objects/Weapons/Guns/Projectiles/meteors.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/meteors.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/meteors.yml index b4e8e77c519..66e380c8d47 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/meteors.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/meteors.yml @@ -107,7 +107,7 @@ thresholds: - trigger: !type:DamageTrigger - damage: 1250 + damage: 300 behaviors: - !type:DoActsBehavior acts: [ "Destruction" ] @@ -147,7 +147,7 @@ thresholds: - trigger: !type:DamageTrigger - damage: 1750 + damage: 500 behaviors: - !type:DoActsBehavior acts: [ "Destruction" ] @@ -175,7 +175,7 @@ thresholds: - trigger: !type:DamageTrigger - damage: 2500 + damage: 1200 behaviors: - !type:DoActsBehavior acts: [ "Destruction" ] @@ -223,4 +223,4 @@ volume: 10 - !type:SpillBehavior solution: blood - - !type:ExplodeBehavior \ No newline at end of file + - !type:ExplodeBehavior From cb90fc42a67ac27f300e16625bfc8252913b6f44 Mon Sep 17 00:00:00 2001 From: PJBot Date: Sun, 15 Sep 2024 20:05:43 +0000 Subject: [PATCH 069/138] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 67d5e36fc3e..4aab16b46a7 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: Vermidia - changes: - - message: Some drink reactions now require shaking with the shaker or stirring - with a spoon - type: Add - id: 6880 - time: '2024-07-07T14:21:53.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29243 - author: Dezzzix changes: - message: Now you can slice food with swords @@ -3915,3 +3907,10 @@ id: 7379 time: '2024-09-15T20:03:15.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/30966 +- author: Plykiya + changes: + - message: Meteors break through less walls now. + type: Tweak + id: 7380 + time: '2024-09-15T20:04:37.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/32109 From 1d4207a9f0a9fbc910449bbb76a627db94639eef Mon Sep 17 00:00:00 2001 From: lzk <124214523+lzk228@users.noreply.github.com> Date: Mon, 16 Sep 2024 01:04:27 +0200 Subject: [PATCH 070/138] Fix plushie cutlass swing animation (#32157) Fix plushie cutlass animation --- Resources/Prototypes/Entities/Objects/Fun/toys.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Resources/Prototypes/Entities/Objects/Fun/toys.yml b/Resources/Prototypes/Entities/Objects/Fun/toys.yml index e27f45f0ccd..62e63935499 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/toys.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/toys.yml @@ -1319,10 +1319,9 @@ sprite: Objects/Weapons/Melee/cutlass.rsi state: foam_icon - type: MeleeWeapon + wideAnimationRotation: -135 attackRate: 1.5 range: 2.0 - angle: 0 - animation: WeaponArcThrust damage: types: Blunt: 0 From aa6d5f95736bf247173a39e4c86e81d38b30f2b1 Mon Sep 17 00:00:00 2001 From: xprospero <116504990+xprospero@users.noreply.github.com> Date: Sun, 15 Sep 2024 13:57:53 -1000 Subject: [PATCH 071/138] Rubber chicken toy (#29637) * -added rubber chicken toy * -Removed faulty SolutionContainerManager type -Replaced default toy squeak sound with rubber chicken sound for on-trigger and on-collide. * fixed raw material cost * adjusted material composition * - Added rubber chicken to CrateFunToyBox - Added rubber chicken to MaintFluffTable under "uncommon group" so that it will spawn in maintenance * Update Resources/Prototypes/Entities/Objects/Fun/toys.yml --------- Co-authored-by: gambesun <116504990+gambesun@users.noreply.github.com> Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> --- Resources/Audio/Items/Toys/attributions.yml | 15 ++++++ .../Audio/Items/Toys/rubber_chicken_1.ogg | Bin 0 -> 10673 bytes .../Audio/Items/Toys/rubber_chicken_2.ogg | Bin 0 -> 9944 bytes .../Audio/Items/Toys/rubber_chicken_3.ogg | Bin 0 -> 12794 bytes .../Prototypes/Catalog/Fills/Crates/fun.yml | 1 + .../Markers/Spawners/Random/maintenance.yml | 1 + .../Prototypes/Entities/Objects/Fun/toys.yml | 49 ++++++++++++++++++ .../SoundCollections/rubber_chicken.yml | 6 +++ .../Textures/Objects/Fun/toys.rsi/meta.json | 5 +- .../Objects/Fun/toys.rsi/rubber_chicken.png | Bin 0 -> 606 bytes 10 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 Resources/Audio/Items/Toys/rubber_chicken_1.ogg create mode 100644 Resources/Audio/Items/Toys/rubber_chicken_2.ogg create mode 100644 Resources/Audio/Items/Toys/rubber_chicken_3.ogg create mode 100644 Resources/Prototypes/SoundCollections/rubber_chicken.yml create mode 100644 Resources/Textures/Objects/Fun/toys.rsi/rubber_chicken.png diff --git a/Resources/Audio/Items/Toys/attributions.yml b/Resources/Audio/Items/Toys/attributions.yml index 290539b9849..162ee8c1c33 100644 --- a/Resources/Audio/Items/Toys/attributions.yml +++ b/Resources/Audio/Items/Toys/attributions.yml @@ -72,3 +72,18 @@ license: "CC-BY-SA-3.0" copyright: "Taken from ss200, made by Daeberdir" source: "https://github.com/ss220-space/Paradise/pull/3756" + +- files: ["rubber_chicken_1.ogg"] + license: "CC0-1.0" + copyright: "Created by xprospero for ss14" + source: "https://github.com/space-wizards/space-station-14/blob/master/Resources/Audio/Items/Toys/rubber_chicken_1.ogg" + +- files: ["rubber_chicken_2.ogg"] + license: "CC0-1.0" + copyright: "Created by xprospero for ss14" + source: "https://github.com/space-wizards/space-station-14/blob/master/Resources/Audio/Items/Toys/rubber_chicken_2.ogg" + +- files: ["rubber_chicken_3.ogg"] + license: "CC0-1.0" + copyright: "Created by xprospero for ss14" + source: "https://github.com/space-wizards/space-station-14/blob/master/Resources/Audio/Items/Toys/rubber_chicken_3.ogg" diff --git a/Resources/Audio/Items/Toys/rubber_chicken_1.ogg b/Resources/Audio/Items/Toys/rubber_chicken_1.ogg new file mode 100644 index 0000000000000000000000000000000000000000..e4ba8155a6cc1d94f9897f6eeb705cffca6ecc75 GIT binary patch literal 10673 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 P`FQ))@FtB@3jF^7vTU_^ literal 0 HcmV?d00001 diff --git a/Resources/Audio/Items/Toys/rubber_chicken_2.ogg b/Resources/Audio/Items/Toys/rubber_chicken_2.ogg new file mode 100644 index 0000000000000000000000000000000000000000..ae79d97ff22920568aa85036c901267f583d3c29 GIT binary patch literal 9944 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 F{{Tkd6yg8? literal 0 HcmV?d00001 diff --git a/Resources/Audio/Items/Toys/rubber_chicken_3.ogg b/Resources/Audio/Items/Toys/rubber_chicken_3.ogg new file mode 100644 index 0000000000000000000000000000000000000000..97d93ed57e727571eaac761c500613444480c94d GIT binary patch literal 12794 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 literal 0 HcmV?d00001 From a61f425bd7773ce33b26cbcfbd2129514ba0a57e Mon Sep 17 00:00:00 2001 From: drakewill-CRL <46307022+drakewill-CRL@users.noreply.github.com> Date: Sun, 15 Sep 2024 20:04:44 -0400 Subject: [PATCH 072/138] Fix sentient produce (#32192) sentient does not apply to produce Co-authored-by: PraxisMapper --- Resources/Prototypes/Hydroponics/randomMutations.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Resources/Prototypes/Hydroponics/randomMutations.yml b/Resources/Prototypes/Hydroponics/randomMutations.yml index 50f6845ec32..8f409a5eaf9 100644 --- a/Resources/Prototypes/Hydroponics/randomMutations.yml +++ b/Resources/Prototypes/Hydroponics/randomMutations.yml @@ -6,7 +6,8 @@ effect: !type:Glow - name: Sentient baseOdds: 0.0072 - appliesToPlant: false # makes the botany tray sentient if true + appliesToProduce: false + persists: false effect: !type:MakeSentient # existing effect. - name: Slippery baseOdds: 0.036 From 63ff116361d40caf5c8318f7eeb9753708907b9c Mon Sep 17 00:00:00 2001 From: PJBot Date: Mon, 16 Sep 2024 00:05:51 +0000 Subject: [PATCH 073/138] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 4aab16b46a7..da0ac0a1c01 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Dezzzix - changes: - - message: Now you can slice food with swords - type: Add - id: 6881 - time: '2024-07-07T14:22:38.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29005 - author: EmoGarbage404 changes: - message: Changed AME power output. Lower injection amounts now produce more power @@ -3914,3 +3907,10 @@ id: 7380 time: '2024-09-15T20:04:37.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/32109 +- author: drakewill-CRL + changes: + - message: Produce harvested from sentient plants are no longer sentient themselves. + type: Fix + id: 7381 + time: '2024-09-16T00:04:45.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/32192 From d872adc7aa2e068ea8a7bb97a8d9acfe81f7c703 Mon Sep 17 00:00:00 2001 From: lzk <124214523+lzk228@users.noreply.github.com> Date: Mon, 16 Sep 2024 02:16:24 +0200 Subject: [PATCH 074/138] Add glass morgue airlock (#32163) --- .../Entities/Structures/Doors/Airlocks/access.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/access.yml b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/access.yml index 51484b9599e..c7951993f14 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/access.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/access.yml @@ -245,7 +245,6 @@ containers: board: [ DoorElectronicsMorgue ] - - type: entity parent: AirlockScience id: AirlockScienceLocked @@ -603,6 +602,15 @@ containers: board: [ DoorElectronicsChemistry ] +- type: entity + parent: AirlockMedicalGlass + id: AirlockMedicalMorgueGlassLocked + suffix: Morgue, Locked + components: + - type: ContainerFill + containers: + board: [ DoorElectronicsMorgue ] + - type: entity parent: AirlockMedicalGlass id: AirlockMedicalGlassLocked From 4adbb8d969dcbf6985d4a35eca57753e4e4b216b Mon Sep 17 00:00:00 2001 From: DrSmugleaf <10968691+DrSmugleaf@users.noreply.github.com> Date: Mon, 16 Sep 2024 01:51:53 -0700 Subject: [PATCH 075/138] Fix examine flickering until you examine something around you (#32205) --- Content.Client/Examine/ExamineSystem.cs | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/Content.Client/Examine/ExamineSystem.cs b/Content.Client/Examine/ExamineSystem.cs index a941f0acff9..1c1f1984de4 100644 --- a/Content.Client/Examine/ExamineSystem.cs +++ b/Content.Client/Examine/ExamineSystem.cs @@ -1,7 +1,12 @@ +using System.Linq; +using System.Numerics; +using System.Threading; using Content.Client.Verbs; using Content.Shared.Examine; using Content.Shared.IdentityManagement; using Content.Shared.Input; +using Content.Shared.Interaction.Events; +using Content.Shared.Item; using Content.Shared.Verbs; using JetBrains.Annotations; using Robust.Client.GameObjects; @@ -12,13 +17,8 @@ using Robust.Shared.Input.Binding; using Robust.Shared.Map; using Robust.Shared.Utility; -using System.Linq; -using System.Numerics; -using System.Threading; using static Content.Shared.Interaction.SharedInteractionSystem; using static Robust.Client.UserInterface.Controls.BoxContainer; -using Content.Shared.Interaction.Events; -using Content.Shared.Item; using Direction = Robust.Shared.Maths.Direction; namespace Content.Client.Examine @@ -35,7 +35,6 @@ public sealed class ExamineSystem : ExamineSystemShared private EntityUid _examinedEntity; private EntityUid _lastExaminedEntity; - private EntityUid _playerEntity; private Popup? _examineTooltipOpen; private ScreenCoordinates _popupPos; private CancellationTokenSource? _requestCancelTokenSource; @@ -74,9 +73,9 @@ private void OnExaminedItemDropped(EntityUid item, ItemComponent comp, DroppedEv public override void Update(float frameTime) { if (_examineTooltipOpen is not {Visible: true}) return; - if (!_examinedEntity.Valid || !_playerEntity.Valid) return; + if (!_examinedEntity.Valid || _playerManager.LocalEntity is not { } player) return; - if (!CanExamine(_playerEntity, _examinedEntity)) + if (!CanExamine(player, _examinedEntity)) CloseTooltip(); } @@ -114,9 +113,8 @@ private bool HandleExamine(in PointerInputCmdHandler.PointerInputCmdArgs args) return false; } - _playerEntity = _playerManager.LocalEntity ?? default; - - if (_playerEntity == default || !CanExamine(_playerEntity, entity)) + if (_playerManager.LocalEntity is not { } player || + !CanExamine(player, entity)) { return false; } From a5850236dd49728ce778ad5a0f51e88e7ea19107 Mon Sep 17 00:00:00 2001 From: PJBot Date: Mon, 16 Sep 2024 08:53:00 +0000 Subject: [PATCH 076/138] Automatic changelog update --- Resources/Changelog/Changelog.yml | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index da0ac0a1c01..b2be978db2e 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,16 +1,4 @@ Entries: -- author: EmoGarbage404 - changes: - - message: Changed AME power output. Lower injection amounts now produce more power - but further injections have diminishing returns. - type: Tweak - - message: Increased damage per injection overclocked AMEs. - type: Tweak - - message: Halved fuel per AME jar. - type: Tweak - id: 6882 - time: '2024-07-07T14:27:52.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29587 - author: Plykiya changes: - message: Hyperzine's effective healing range has been changed from 70 to 120, @@ -3914,3 +3902,11 @@ id: 7381 time: '2024-09-16T00:04:45.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/32192 +- author: DrSmugleaf + changes: + - message: Fixed examine sometimes flickering and closing until you examine something + around you. + type: Fix + id: 7382 + time: '2024-09-16T08:51:54.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/32205 From 65bf3c61b637e1d8eaea57c2187d00fc8519ea40 Mon Sep 17 00:00:00 2001 From: ArtisticRoomba <145879011+ArtisticRoomba@users.noreply.github.com> Date: Mon, 16 Sep 2024 01:59:00 -0700 Subject: [PATCH 077/138] Adds the syndicate Booze-O-Mat (Bruise-O-Mat) to nukie planet (#32107) --- .../advertisements/vending/bruiseomat.ftl | 43 +++++++++ Resources/Maps/Nonstations/nukieplanet.yml | 2 +- .../VendingMachines/advertisements.yml | 6 ++ .../Catalog/VendingMachines/goodbyes.yml | 6 ++ .../Structures/Machines/vending_machines.yml | 35 +++++++ .../VendingMachines/bruiseomat.rsi/broken.png | Bin 0 -> 1104 bytes .../bruiseomat.rsi/deny-unshaded.png | Bin 0 -> 1616 bytes .../VendingMachines/bruiseomat.rsi/meta.json | 89 ++++++++++++++++++ .../bruiseomat.rsi/normal-unshaded.png | Bin 0 -> 4617 bytes .../VendingMachines/bruiseomat.rsi/off.png | Bin 0 -> 786 bytes .../VendingMachines/bruiseomat.rsi/panel.png | Bin 0 -> 247 bytes 11 files changed, 180 insertions(+), 1 deletion(-) create mode 100644 Resources/Locale/en-US/advertisements/vending/bruiseomat.ftl create mode 100644 Resources/Textures/Structures/Machines/VendingMachines/bruiseomat.rsi/broken.png create mode 100644 Resources/Textures/Structures/Machines/VendingMachines/bruiseomat.rsi/deny-unshaded.png create mode 100644 Resources/Textures/Structures/Machines/VendingMachines/bruiseomat.rsi/meta.json create mode 100644 Resources/Textures/Structures/Machines/VendingMachines/bruiseomat.rsi/normal-unshaded.png create mode 100644 Resources/Textures/Structures/Machines/VendingMachines/bruiseomat.rsi/off.png create mode 100644 Resources/Textures/Structures/Machines/VendingMachines/bruiseomat.rsi/panel.png diff --git a/Resources/Locale/en-US/advertisements/vending/bruiseomat.ftl b/Resources/Locale/en-US/advertisements/vending/bruiseomat.ftl new file mode 100644 index 00000000000..a8cb903efe2 --- /dev/null +++ b/Resources/Locale/en-US/advertisements/vending/bruiseomat.ftl @@ -0,0 +1,43 @@ +advertisement-bruiseomat-1 = I VOTE WAROPS!!! +advertisement-bruiseomat-2 = Who has TC? +advertisement-bruiseomat-3 = Did anyone buy an EMAG? +advertisement-bruiseomat-4 = I wanna go back to my home station... +advertisement-bruiseomat-5 = Beware of the Mime and Clown. BEWARE! +advertisement-bruiseomat-6 = A nuke a day keeps the deathsquad at bay! +advertisement-bruiseomat-7 = You'll never be able to match MY mixing, Agent! +advertisement-bruiseomat-8 = Thirsting for blood? I got you covered! +advertisement-bruiseomat-9 = If they didn't want us to blow up the station, then why would they leave the disk so unsecured? +advertisement-bruiseomat-10 = They say an eye for an eye makes the whole world blind. So try a nuke instead! +advertisement-bruiseomat-11 = I hunger for blood! +advertisement-bruiseomat-12 = Drink up before the mission! +advertisement-bruiseomat-13 = Man, I didn't know I got moved back to Cadet City! +advertisement-bruiseomat-14 = Sicker than your average Booze-O-Mat! +advertisement-bruiseomat-15 = Nuke ops will continue until robustness improves. +thankyou-bruiseomat-1 = Good luck, schmuck! You're gonna need it! +thankyou-bruiseomat-2 = Show 'em the Gorlex Style! +thankyou-bruiseomat-3 = Don't forget to stay hydrated! +thankyou-bruiseomat-4 = You noted down the codes, right? +thankyou-bruiseomat-5 = Don't forget the nuke! +thankyou-bruiseomat-6 = I hope those are noslips. +thankyou-bruiseomat-7 = Please let this be a normal team... +thankyou-bruiseomat-8 = Seems like the station isn't the only thing getting hammered today. +thankyou-bruiseomat-9 = What the hell did you buy? +thankyou-bruiseomat-10 = Give it up for the flukeops professionals! +thankyou-bruiseomat-11 = Death to NanoTrasen!!! +thankyou-bruiseomat-12 = Really? That's your plan? +thankyou-bruiseomat-13 = In my endless life, never have I ever seen that loadout. +thankyou-bruiseomat-14 = Get that captain! +thankyou-bruiseomat-15 = Don't run off by yourself, now! +thankyou-bruiseomat-16 = Y'all are taking too long! +thankyou-bruiseomat-17 = They won't see that coming! +thankyou-bruiseomat-18 = Remember your pinpointer! +thankyou-bruiseomat-19 = See you soon! Or maybe never again, that one's more likely! +thankyou-bruiseomat-20 = Rescue another one of me! I need a friend! +thankyou-bruiseomat-21 = You're going to sober up before the mission, right? +thankyou-bruiseomat-22 = 5 telecrystal says you won't make it to the shuttle before you fall over. +thankyou-bruiseomat-23 = The soda fountain's over there, lightweight. +thankyou-bruiseomat-24 = Did you spend your TC on cat ears? +thankyou-bruiseomat-25 = Really? That's what you wanted to drink? +thankyou-bruiseomat-26 = Take a shot, give a shot! +thankyou-bruiseomat-27 = How many drinks have you had now? I've lost count. +thankyou-bruiseomat-28 = When the bosses say "die trying" they mean dying in BATTLE, not at the bar. diff --git a/Resources/Maps/Nonstations/nukieplanet.yml b/Resources/Maps/Nonstations/nukieplanet.yml index 2063451a0ee..665657f7dda 100644 --- a/Resources/Maps/Nonstations/nukieplanet.yml +++ b/Resources/Maps/Nonstations/nukieplanet.yml @@ -13721,7 +13721,7 @@ entities: - type: Transform pos: 3.5882664,-8.344303 parent: 104 -- proto: VendingMachineBooze +- proto: VendingMachineBoozeSyndicate entities: - uid: 1380 components: diff --git a/Resources/Prototypes/Catalog/VendingMachines/advertisements.yml b/Resources/Prototypes/Catalog/VendingMachines/advertisements.yml index 5f6806afbb1..9314de97914 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/advertisements.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/advertisements.yml @@ -22,6 +22,12 @@ prefix: advertisement-boozeomat- count: 19 +- type: localizedDataset + id: BruiseOMatAds + values: + prefix: advertisement-bruiseomat- + count: 15 + - type: localizedDataset id: CargoDrobeAds values: diff --git a/Resources/Prototypes/Catalog/VendingMachines/goodbyes.yml b/Resources/Prototypes/Catalog/VendingMachines/goodbyes.yml index 5a3d91db116..fd4e53acaa7 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/goodbyes.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/goodbyes.yml @@ -4,6 +4,12 @@ prefix: thankyou-boozeomat- count: 3 +- type: localizedDataset + id: BruiseOMatGoodbyes + values: + prefix: thankyou-bruiseomat- + count: 28 + - type: localizedDataset id: ChangGoodbyes values: diff --git a/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml b/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml index 65f40ab3e49..a6cf9ef0e30 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml @@ -199,6 +199,41 @@ - Bartender - Drinks +- type: entity + parent: VendingMachineBooze + id: VendingMachineBoozeSyndicate # syndie booze-o-mat for nukie outpost + name: Bruise-O-Mat + description: A refurbished Booze-O-Mat for boosting operative morale. An imprint of a blood-red hardsuit is visible on one side, and the paint seems ashed off on the other side. + components: + - type: VendingMachine + pack: BoozeOMatInventory + offState: off + brokenState: broken + normalState: normal-unshaded + denyState: deny-unshaded + loopDeny: false + - type: Advertise + pack: BruiseOMatAds + - type: SpeakOnUIClosed + pack: BruiseOMatGoodbyes + - type: Speech + - type: Sprite + sprite: Structures/Machines/VendingMachines/bruiseomat.rsi + layers: + - state: "off" + map: ["enum.VendingMachineVisualLayers.Base"] + - state: "off" + map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] + shader: unshaded + - state: panel + map: ["enum.WiresVisualLayers.MaintenancePanel"] + - type: AccessReader + access: [["SyndicateAgent"]] + - type: GuideHelp + guides: + - Bartender + - Drinks + - type: entity parent: VendingMachine id: VendingMachineCart diff --git a/Resources/Textures/Structures/Machines/VendingMachines/bruiseomat.rsi/broken.png b/Resources/Textures/Structures/Machines/VendingMachines/bruiseomat.rsi/broken.png new file mode 100644 index 0000000000000000000000000000000000000000..1df632306540fd93c9d253dc312b1aaa50abc43e GIT binary patch literal 1104 zcmV-W1h4yvP)Px(3Q0skR9J=WmS1RFRUF4Z=l*G$nwqqtH5o1Fb4?#wK`1sN)lI=sX}b>XpG_@n zu*yLCq6~Dny|_tj)s}9n%yqihu4O|Q!hBNSHqlail$0P;wl=v-$&!1M93S$BB{yMh z2knbrINW=G=lp)Z&-tBm&%MIy^-6Y88i3pF#^dqqXyRxzieVU80FTE*V`Jlv0st6> zfwJRSOY}d$t^;TQjg5`e)z$5I@|Bepv{)=gI2=X@v7^bu;V`jSEL(xRmX?;b9nkOh zZ`$AQ_ZRMq0OIlZwgI;5uaz1`Kl}&)p$MjDFO!lg0E()T%%}|a?nh=M-`)6`{GzS@ zb*tb%6pNuhy9WTr$PtngQ^ecask!wV*5Chdv9`7-pY1J}2?m)72C+;Fp{QsgUDW^8 z<#`$!8W`z6@X*-_AqvSW$p#Qf2qFnV3I!u6xMyj^Q-Y0T2FtP#Lh$hylY~}6L=A(e zVN?vB7@wr-xo3#CwO1TtTLO(51Zr47> zt}lWR821d~)e;@aK+hZOdD_R>=?fKu#@pISy)!`l)$2fZDXc?pmmOWBt80dtS-h)#vkVDS24{Ek8pb zl}clpCI|O+(DB0aD2js5>tpQH8P;p;GmS(dn@ZZ$)Ks{)Z9+v+Q4}@zCS>LFc{y_8 z1g2>+cIph~Q%_P|U5&%xz~OKd`G-Owx?X>|&_baQ06m(M9?cGItALXGDyGR2^uE%; z>gvA$II0{Re6ODiSARrRRTRbk1#N9@W$f#jqUW`>HReO>(iX{m8pOYK-cv` zlTy;N_eFGFXLNWFhr6D+UvKm2m**H6I8Ye(D6#=mxzbd*(&#m54t2eT`*AnpSFVvv zB$2s|A=DI8b911kvTYMe=US<3dq8Hg*Q4EUv3h5f*&8>}TslG#d@$I{XVd3URRu)> z%KSw2_4T1?8bS!9lt?L=n3$-z2W$X$ZvO$m$=o%s(|`V6adrg|4-O_(; W9$!}jmzmK30000 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Machines/VendingMachines/bruiseomat.rsi/off.png b/Resources/Textures/Structures/Machines/VendingMachines/bruiseomat.rsi/off.png new file mode 100644 index 0000000000000000000000000000000000000000..c3427b7188c359f38b6f49a481f84cd3199bf0e8 GIT binary patch literal 786 zcmV+t1MU2YP)Px%%t=H+R9J=Wmd#GvKomyL*kcExL@`t#K@~*1Mq$AN@Di1>tkh*!eH0`l#0sg) zN_~`8su1e3f<|2w3W?)1KNH*2g^h_F2aeX6%`-{@R4Nr5 z$62UxtJT7F-3Y*O9IDmoLID6=*Tq=4YexS8o*h5}RI621R#p~nesOVu^gNG7qk#}& zq2`T71JCoK2;A!Q^mOh8Yqi?c^J}$Q(oO+%yWP0~=AAFIH=ONP0BAq}zBU0cOp`%q zqLiXisUU>l_NCo?|B}pq>v>qOU*?((fBfQOxqLr>X-0-xM-Va$5{N`vKUvO<0W|yB zh2uy35C{=M(DuA1G0z2XoM^W_RYV9uuj69db~3J%;zhZTn)Bx=0d#UWNAJKdOMF6# z0|TqqrvPX)cNy?FO|FC*JhKNvfFbBEX)H7az;E@R#2oI6fQTuCh<@l>u6uPXCH(w7 z!A-LK5J0;f#H|iiX3Ui%k9SnA$MSO4;(m<*SXS0HN<1KyjH4RF*Uin%napzmq`dp) zeLp}cg;ObD7;w`Zu)4a6eR;)AaeSxEW^*djt*x!e0EQ6(1VNA;0>Hk!Lanc{gZx9~_;qy}ivF83BLxd#Uxt0pbc5Oh`AizQ%Ak#57F|WBgOx+uP&d z=p@y@zP=tao(SM|I;p-80=KP__B3JM-`~fwEQZ4&op`-^9Dz>{MPM`ul~TyEh3^fq zZ5yK)9VB5lU5W?HuQ33-6uo;Lf>NYDd>tP`!t@`k2U+E3R9+zpqwC*RfGkJRkR=P% zQ52RT=ru7-1H*v4YFw|^ky0XrKx>WGn#04x>2u)f>$i!!nDlpJwD^Q!NWb4tqLqM6 zn**~}vaF7ek8|&5jdKC!sbr(t-QAsejwqE%8enH<=TYXf>g?<+4e(t02cZlCuO2cJ QWdHyG07*qoM6N<$g6wW>IsgCw literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Machines/VendingMachines/bruiseomat.rsi/panel.png b/Resources/Textures/Structures/Machines/VendingMachines/bruiseomat.rsi/panel.png new file mode 100644 index 0000000000000000000000000000000000000000..60dbf76b85e3f9f18a80a5d810366360f199f9ba GIT binary patch literal 247 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5D7ezo z#WAE}&f6=7T!$P4STD$nyx(**th!lbTG+gU4O4I5WVQBAblh;7aZS)HW1p?;A5?^9 zb}-r=aQWcBegDt=^u*^gDmWAx7?{As83xUzcF%3*%`NUQ6iZ{!jbCq-Q*J!RpFiey zc-}9TsCApye80i6k^RM4(L!q(_7=?p)&14F8mA4`-51%AAr+#;>S9-9+%PTP=>_`{ nkp}Ze*1zZXcQ7#3iG5&UGSGT7l{r%o=x7E{S3j3^P6 Date: Mon, 16 Sep 2024 09:00:06 +0000 Subject: [PATCH 078/138] Automatic changelog update --- Resources/Changelog/Changelog.yml | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index b2be978db2e..11b88c97d5c 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: Plykiya - changes: - - message: Hyperzine's effective healing range has been changed from 70 to 120, - to anything above 70 total damage. - type: Tweak - id: 6883 - time: '2024-07-07T14:28:13.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29712 - author: Tayrtahn changes: - message: Fixed admin ghosts briefly becoming visible when a news article is published. @@ -3910,3 +3902,12 @@ id: 7382 time: '2024-09-16T08:51:54.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/32205 +- author: ArtisticRoomba + changes: + - message: The Bruise-O-Mat alcohol vendor has been added to the nukie outpost, + for all your pre-op drinking needs. Seems to have developed a witty personality, + too... + type: Add + id: 7383 + time: '2024-09-16T08:59:00.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/32107 From 65329ab38d9a9230b495b4a87160c4b724b88802 Mon Sep 17 00:00:00 2001 From: ArtisticRoomba <145879011+ArtisticRoomba@users.noreply.github.com> Date: Mon, 16 Sep 2024 03:01:49 -0700 Subject: [PATCH 079/138] Change the binary translator key's contraband designation to syndicate contraband + minor sprite change for consistency (#32193) * adds new icon, changes binary key icon and frame, changes contraband designation * added back the regular key as admeme because it makes sense (why am I not thinking about these things) * hehe I cannot read! --- .../Prototypes/Catalog/uplink_catalog.yml | 6 +++--- .../Objects/Devices/encryption_keys.yml | 17 ++++++++++++++++- .../Devices/encryption_keys.rsi/borg_label.png | Bin 0 -> 149 bytes .../Devices/encryption_keys.rsi/meta.json | 7 ++++--- 4 files changed, 23 insertions(+), 7 deletions(-) create mode 100644 Resources/Textures/Objects/Devices/encryption_keys.rsi/borg_label.png diff --git a/Resources/Prototypes/Catalog/uplink_catalog.yml b/Resources/Prototypes/Catalog/uplink_catalog.yml index 394a06516be..efa288a44b8 100644 --- a/Resources/Prototypes/Catalog/uplink_catalog.yml +++ b/Resources/Prototypes/Catalog/uplink_catalog.yml @@ -773,8 +773,8 @@ id: UplinkBinaryTranslatorKey name: uplink-binary-translator-key-name description: uplink-binary-translator-key-desc - icon: { sprite: /Textures/Objects/Devices/encryption_keys.rsi, state: rd_label } - productEntity: EncryptionKeyBinary + icon: { sprite: /Textures/Objects/Devices/encryption_keys.rsi, state: borg_label } + productEntity: EncryptionKeyBinarySyndicate cost: Telecrystal: 1 categories: @@ -2046,4 +2046,4 @@ - !type:BuyerJobCondition whitelist: - Chef - - Mime \ No newline at end of file + - Mime diff --git a/Resources/Prototypes/Entities/Objects/Devices/encryption_keys.yml b/Resources/Prototypes/Entities/Objects/Devices/encryption_keys.yml index 7186f9f34ab..25d81a6f83c 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/encryption_keys.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/encryption_keys.yml @@ -227,7 +227,22 @@ - type: Sprite layers: - state: crypt_silver - - state: rd_label + - state: borg_label + +- type: entity + parent: [ EncryptionKey, BaseSyndicateContraband ] + id: EncryptionKeyBinarySyndicate + name: binary translator key + description: A syndicate encryption key that translates binary signals used by silicons. + components: + - type: EncryptionKey + channels: + - Binary + defaultChannel: Binary + - type: Sprite + layers: + - state: crypt_red + - state: borg_label - type: entity parent: EncryptionKey diff --git a/Resources/Textures/Objects/Devices/encryption_keys.rsi/borg_label.png b/Resources/Textures/Objects/Devices/encryption_keys.rsi/borg_label.png new file mode 100644 index 0000000000000000000000000000000000000000..2b56e167730682294aca3f6c0465c838176a3bfb GIT binary patch literal 149 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}{+=$5ArY-_ zFBtMQ81Oh>>|nl~ezNm$2 Date: Mon, 16 Sep 2024 10:02:55 +0000 Subject: [PATCH 080/138] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 11b88c97d5c..cf6948f5d97 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Tayrtahn - changes: - - message: Fixed admin ghosts briefly becoming visible when a news article is published. - type: Fix - id: 6884 - time: '2024-07-08T03:33:17.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29801 - author: slarticodefast changes: - message: Improved throwing calculations. Thrown items now stop moving exactly @@ -3911,3 +3904,11 @@ id: 7383 time: '2024-09-16T08:59:00.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/32107 +- author: ArtisticRoomba + changes: + - message: The binary translator key in the syndie uplink is now correctly marked + as syndicate contraband. + type: Tweak + id: 7384 + time: '2024-09-16T10:01:49.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/32193 From b2dbad37796a4d7cb09057a6ff3934cc781fdda3 Mon Sep 17 00:00:00 2001 From: august-sun <45527070+august-sun@users.noreply.github.com> Date: Mon, 16 Sep 2024 04:37:26 -0600 Subject: [PATCH 081/138] Immovable Rod Spawn Addition: Lizard Plushie (#32113) * a deadly weh * Updated meteorswarms.yml Updated probabilities to match exactly 1 * Updated immovable_rod.yml Removed rotation --------- Co-authored-by: august-sun <45527070+august.sun@users.noreply.github.com> --- .../Entities/Objects/Fun/immovable_rod.yml | 13 ++++++++++++- .../Prototypes/GameRules/meteorswarms.yml | 19 +++++++++++-------- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/Resources/Prototypes/Entities/Objects/Fun/immovable_rod.yml b/Resources/Prototypes/Entities/Objects/Fun/immovable_rod.yml index 69f0ed415eb..0bee05aa6ad 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/immovable_rod.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/immovable_rod.yml @@ -1,4 +1,4 @@ -- type: entity +- type: entity id: ImmovableRod name: immovable rod description: You can sense that it's hungry. That's usually a bad sign. @@ -177,3 +177,14 @@ state: icon rotation: 225 noRot: false + +- type: entity + parent: ImmovableRodKeepTilesStill + id: ImmovableRodWeh + name: immovable weh + description: WEH! + components: + - type: Sprite + sprite: Objects/Fun/toys.rsi + state: plushie_lizard + noRot: false diff --git a/Resources/Prototypes/GameRules/meteorswarms.yml b/Resources/Prototypes/GameRules/meteorswarms.yml index 6203ee35abf..6cfcc536bd3 100644 --- a/Resources/Prototypes/GameRules/meteorswarms.yml +++ b/Resources/Prototypes/GameRules/meteorswarms.yml @@ -211,26 +211,29 @@ - type: ImmovableRodRule rodPrototypes: - id: ImmovableRodKeepTilesStill - prob: 0.95 + prob: 0.94 orGroup: rodProto - id: ImmovableRodMop - prob: 0.0072 + prob: 0.0075 orGroup: rodProto - id: ImmovableRodShark - prob: 0.0072 + prob: 0.0075 orGroup: rodProto - id: ImmovableRodClown - prob: 0.0072 + prob: 0.0075 orGroup: rodProto - id: ImmovableRodBanana - prob: 0.0072 + prob: 0.0075 orGroup: rodProto - id: ImmovableRodHammer - prob: 0.0072 + prob: 0.0075 orGroup: rodProto - id: ImmovableRodThrongler - prob: 0.0072 + prob: 0.0075 orGroup: rodProto - id: ImmovableRodGibstick - prob: 0.0072 + prob: 0.0075 + orGroup: rodProto + - id: ImmovableRodWeh + prob: 0.0075 orGroup: rodProto From 4abb6a7dd1c9b66734893fb4c01721239c71d231 Mon Sep 17 00:00:00 2001 From: MissKay1994 <15877268+MissKay1994@users.noreply.github.com> Date: Mon, 16 Sep 2024 08:45:15 -0400 Subject: [PATCH 082/138] Lizards now metabolize chocolate (#32147) * Eat the chocolate * Update toxins.yml * fully delete threshold lines * Update snacks.yml * Fix tags Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> --- .../Prototypes/Entities/Objects/Consumable/Food/snacks.yml | 4 ++++ Resources/Prototypes/Reagents/toxins.yml | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/snacks.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/snacks.yml index ff0504d39ea..e9e57f79ce4 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/snacks.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/snacks.yml @@ -129,6 +129,10 @@ - type: Sprite state: chocolatebar-open - type: Item + - type: Tag + tags: + - FoodSnack + - ReptilianFood - type: SolutionContainerManager solutions: food: diff --git a/Resources/Prototypes/Reagents/toxins.yml b/Resources/Prototypes/Reagents/toxins.yml index e53c767a7e7..6235136dbc2 100644 --- a/Resources/Prototypes/Reagents/toxins.yml +++ b/Resources/Prototypes/Reagents/toxins.yml @@ -402,8 +402,6 @@ effects: - !type:HealthChange conditions: - - !type:ReagentThreshold - min: 1 - !type:OrganType type: Animal # Applying damage to the mobs with lower metabolism capabilities damage: @@ -412,8 +410,6 @@ - !type:ChemVomit probability: 0.04 #Scaled for time, not metabolismrate. conditions: - - !type:ReagentThreshold - min: 3 - !type:OrganType type: Animal From af53d553292cb958a8967d207b112180bcdc59d2 Mon Sep 17 00:00:00 2001 From: PJBot Date: Mon, 16 Sep 2024 12:46:21 +0000 Subject: [PATCH 083/138] Automatic changelog update --- Resources/Changelog/Changelog.yml | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index cf6948f5d97..27926b7a908 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,13 +1,4 @@ Entries: -- author: slarticodefast - changes: - - message: Improved throwing calculations. Thrown items now stop moving exactly - below your cursor. Throwing weapons will land at your cursor and then slide - until stopped by friction. - type: Tweak - id: 6885 - time: '2024-07-08T09:03:53.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29726 - author: Errant changes: - message: Vox now have their entry in the guidebook. @@ -3912,3 +3903,10 @@ id: 7384 time: '2024-09-16T10:01:49.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/32193 +- author: MissKay1994 + changes: + - message: Lizards are now poisoned by hot chocolate + type: Fix + id: 7385 + time: '2024-09-16T12:45:15.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/32147 From ccc5f61584b4017c315cb3df1178eb8a4e391194 Mon Sep 17 00:00:00 2001 From: chavonadelal <156101927+chavonadelal@users.noreply.github.com> Date: Mon, 16 Sep 2024 15:50:14 +0300 Subject: [PATCH 084/138] Localization of steal targets (#30153) * Localization of steal targets * Correction of localization of theft objects * The second correction of the localization of theft targets * Update steal-target-groups.ftl Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com> * Revision of the localization method * Choosing a simple option for localization * Fix TechnologyDisk name * Corrections based on feedback received * correction of declension --------- Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com> --- .../Systems/StealConditionSystem.cs | 9 +- .../Prototypes/StealTargetGroupPrototype.cs | 2 +- .../conditions/steal-target-groups.ftl | 66 +++++++++++ .../en-US/objectives/conditions/steal.ftl | 2 +- .../Objectives/stealTargetGroups.yml | 112 +++++++++--------- 5 files changed, 128 insertions(+), 63 deletions(-) create mode 100644 Resources/Locale/en-US/objectives/conditions/steal-target-groups.ftl diff --git a/Content.Server/Objectives/Systems/StealConditionSystem.cs b/Content.Server/Objectives/Systems/StealConditionSystem.cs index 2c9244cf7d5..be34a80fe34 100644 --- a/Content.Server/Objectives/Systems/StealConditionSystem.cs +++ b/Content.Server/Objectives/Systems/StealConditionSystem.cs @@ -72,14 +72,15 @@ private void OnAssigned(Entity condition, ref Objective private void OnAfterAssign(Entity condition, ref ObjectiveAfterAssignEvent args) { var group = _proto.Index(condition.Comp.StealGroup); + string localizedName = Loc.GetString(group.Name); var title =condition.Comp.OwnerText == null - ? Loc.GetString(condition.Comp.ObjectiveNoOwnerText, ("itemName", group.Name)) - : Loc.GetString(condition.Comp.ObjectiveText, ("owner", Loc.GetString(condition.Comp.OwnerText)), ("itemName", group.Name)); + ? Loc.GetString(condition.Comp.ObjectiveNoOwnerText, ("itemName", localizedName)) + : Loc.GetString(condition.Comp.ObjectiveText, ("owner", Loc.GetString(condition.Comp.OwnerText)), ("itemName", localizedName)); var description = condition.Comp.CollectionSize > 1 - ? Loc.GetString(condition.Comp.DescriptionMultiplyText, ("itemName", group.Name), ("count", condition.Comp.CollectionSize)) - : Loc.GetString(condition.Comp.DescriptionText, ("itemName", group.Name)); + ? Loc.GetString(condition.Comp.DescriptionMultiplyText, ("itemName", localizedName), ("count", condition.Comp.CollectionSize)) + : Loc.GetString(condition.Comp.DescriptionText, ("itemName", localizedName)); _metaData.SetEntityName(condition.Owner, title, args.Meta); _metaData.SetEntityDescription(condition.Owner, description, args.Meta); diff --git a/Content.Shared/Objectives/Prototypes/StealTargetGroupPrototype.cs b/Content.Shared/Objectives/Prototypes/StealTargetGroupPrototype.cs index 2730acb9aca..bc2af0eb092 100644 --- a/Content.Shared/Objectives/Prototypes/StealTargetGroupPrototype.cs +++ b/Content.Shared/Objectives/Prototypes/StealTargetGroupPrototype.cs @@ -10,6 +10,6 @@ namespace Content.Shared.Objectives; public sealed partial class StealTargetGroupPrototype : IPrototype { [IdDataField] public string ID { get; private set; } = default!; - [DataField] public string Name { get; private set; } = string.Empty; + [DataField] public LocId Name { get; private set; } = string.Empty; [DataField] public SpriteSpecifier Sprite { get; private set; } = SpriteSpecifier.Invalid; } diff --git a/Resources/Locale/en-US/objectives/conditions/steal-target-groups.ftl b/Resources/Locale/en-US/objectives/conditions/steal-target-groups.ftl new file mode 100644 index 00000000000..91b3c92b1c3 --- /dev/null +++ b/Resources/Locale/en-US/objectives/conditions/steal-target-groups.ftl @@ -0,0 +1,66 @@ +# Traitor single items +steal-target-groups-hypospray = hypospray +steal-target-groups-handheld-crew-monitor = handheld crew monitor +steal-target-groups-clothing-outer-hardsuit-rd = experimental research hardsuit +steal-target-groups-hand-teleporter = hand teleporter +steal-target-groups-clothing-shoes-boots-mag-adv = advanced magboots +steal-target-groups-box-folder-qm-clipboard = requisition digi-board +steal-target-groups-food-meat-corgi = prime-cut corgi meat +steal-target-groups-captain-id-card = captain ID card +steal-target-groups-jetpack-captain-filled = captain's jetpack +steal-target-groups-weapon-antique-laser = antique laser pistol +steal-target-groups-nuke-disk = nuclear authentication disk +steal-target-groups-weapon-energy-shot-gun = energy shotgun + +# Thief Collection +steal-target-groups-figurines = figurine +steal-target-groups-heads-cloaks = head's cloak +steal-target-groups-heads-bedsheets = head's bedsheet +steal-target-groups-stamps = stamp +steal-target-groups-door-remotes = door remote +steal-target-groups-encryption-keys = encryption key +steal-target-groups-technology-disks = technology disk +steal-target-groups-id-cards = ID Card +steal-target-groups-lamps = LAMP + +# Thief single item +steal-target-groups-forensic-scanner = forensic scanner +steal-target-groups-flippo-engraved-lighter = detective's Flippo engraved lighter +steal-target-groups-ammo-tech-fab-circuitboard = ammo techfab circuit board +steal-target-groups-clothing-head-hat-warden = warden's cap +steal-target-groups-clothing-outer-hardsuit-void-paramed = paramedic void suit +steal-target-groups-medical-tech-fab-circuitboard = medical techfab machine board +steal-target-groups-clothing-headset-alt-medical = chief medical officer's over-ear headset +steal-target-groups-research-and-development-server-machine-circuitboard = R&D server machine board +steal-target-groups-fire-axe = fireaxe +steal-target-groups-ame-part-flatpack = AME flatpack +steal-target-groups-salvage-expeditions-computer-circuitboard = salvage expeditions computer board +steal-target-groups-cargo-shuttle-console-circuitboard = cargo shuttle console board +steal-target-groups-clothing-eyes-hud-beer = beer goggles +steal-target-groups-bible = bible +steal-target-groups-clothing-neck-goldmedal = gold medal of crewmanship +steal-target-groups-clothing-neck-clownmedal = clown medal + +# Thief structures +steal-target-groups-teg = teg generator part +steal-target-groups-freezer-heater = freezer or heater +steal-target-groups-altar-nanotrasen = nanotrasen altar (any) + +steal-target-groups-nuclear-bomb = nuclear fission explosive +steal-target-groups-fax-machine-captain = captain long range fax machine +steal-target-groups-chem-dispenser = chemical dispenser +steal-target-groups-xeno-artifact = alien artifact +steal-target-groups-booze-dispenser = booze dispenser +steal-target-groups-plant-rd = "RD's potted plant" +steal-target-groups-toilet-golden-dirty-water = golden toilet + +# Thief Animal +steal-target-groups-animal-named-cat = CMO's Cat + +steal-target-groups-animal-ian = Ian +steal-target-groups-animal-mc-griff = McGriff +steal-target-groups-animal-walter = Walter +steal-target-groups-animal-morty = Morty +steal-target-groups-animal-renault = Renault +steal-target-groups-animal-shiva = Shiva +steal-target-groups-animal-tropico = Tropico diff --git a/Resources/Locale/en-US/objectives/conditions/steal.ftl b/Resources/Locale/en-US/objectives/conditions/steal.ftl index 00c8e0fdaf9..1f11bf7196b 100644 --- a/Resources/Locale/en-US/objectives/conditions/steal.ftl +++ b/Resources/Locale/en-US/objectives/conditions/steal.ftl @@ -8,4 +8,4 @@ objective-condition-steal-Ian = head of personnel's corgi objective-condition-thief-description = The {$itemName} would be a great addition to my collection! objective-condition-thief-animal-description = The {$itemName} would be a great addition to my collection! Most importantly, alive. -objective-condition-thief-multiply-description = I need to get {$count} {MAKEPLURAL($itemName)} and take them with me. +objective-condition-thief-multiply-description = I need to get {$count} {MAKEPLURAL($itemName)} (any) and take them with me. diff --git a/Resources/Prototypes/Objectives/stealTargetGroups.yml b/Resources/Prototypes/Objectives/stealTargetGroups.yml index b22e952e7e6..48f56e2bfcd 100644 --- a/Resources/Prototypes/Objectives/stealTargetGroups.yml +++ b/Resources/Prototypes/Objectives/stealTargetGroups.yml @@ -2,84 +2,84 @@ - type: stealTargetGroup id: Hypospray - name: hypospray + name: steal-target-groups-hypospray sprite: sprite: Objects/Specific/Medical/hypospray.rsi state: hypo - type: stealTargetGroup id: HandheldCrewMonitor - name: handheld crew monitor + name: steal-target-groups-handheld-crew-monitor sprite: sprite: Objects/Specific/Medical/handheldcrewmonitor.rsi state: scanner - type: stealTargetGroup id: ClothingOuterHardsuitRd - name: experimental research hardsuit + name: steal-target-groups-clothing-outer-hardsuit-rd sprite: sprite: Clothing/OuterClothing/Hardsuits/rd.rsi state: icon - type: stealTargetGroup id: HandTeleporter - name: hand teleporter + name: steal-target-groups-hand-teleporter sprite: sprite: Objects/Devices/hand_teleporter.rsi state: icon - type: stealTargetGroup id: ClothingShoesBootsMagAdv - name: advanced magboots + name: steal-target-groups-clothing-shoes-boots-mag-adv sprite: sprite: Clothing/Shoes/Boots/magboots-advanced.rsi state: icon - type: stealTargetGroup id: BoxFolderQmClipboard - name: requisition digi-board + name: steal-target-groups-box-folder-qm-clipboard sprite: sprite: Objects/Misc/qm_clipboard.rsi state: qm_clipboard - type: stealTargetGroup id: FoodMeatCorgi - name: prime-cut corgi meat + name: steal-target-groups-food-meat-corgi sprite: sprite: Objects/Consumable/Food/meat.rsi state: corgi # - type: stealTargetGroup id: CaptainIDCard - name: captain ID card + name: steal-target-groups-captain-id-card sprite: sprite: Objects/Misc/id_cards.rsi state: ert_commander #no one will know the difference. - type: stealTargetGroup id: JetpackCaptainFilled - name: captain's jetpack + name: steal-target-groups-jetpack-captain-filled sprite: sprite: Objects/Tanks/Jetpacks/captain.rsi state: icon - type: stealTargetGroup id: WeaponAntiqueLaser - name: antique laser pistol + name: steal-target-groups-weapon-antique-laser sprite: sprite: Objects/Weapons/Guns/Battery/antiquelasergun.rsi state: base - type: stealTargetGroup id: NukeDisk - name: nuclear authentication disk + name: steal-target-groups-nuke-disk sprite: sprite: Objects/Misc/nukedisk.rsi state: icon - type: stealTargetGroup id: WeaponEnergyShotgun - name: energy shotgun + name: steal-target-groups-weapon-energy-shot-gun sprite: sprite: Objects/Weapons/Guns/Battery/energy_shotgun.rsi state: base @@ -88,63 +88,63 @@ - type: stealTargetGroup id: Figurines - name: figurines (any) + name: steal-target-groups-figurines sprite: sprite: Objects/Fun/figurines.rsi state: figurine_spawner - type: stealTargetGroup id: HeadCloak - name: head's cloaks (any) + name: steal-target-groups-heads-cloaks sprite: sprite: Clothing/Neck/Cloaks/cap.rsi state: icon - type: stealTargetGroup id: HeadBedsheet - name: head's bedsheets (any) + name: steal-target-groups-heads-bedsheets sprite: sprite: Objects/Misc/bedsheets.rsi state: sheetNT - type: stealTargetGroup id: Stamp - name: stamps (any) + name: steal-target-groups-stamps sprite: sprite: Objects/Misc/stamps.rsi state: stamp-cap - type: stealTargetGroup id: DoorRemote - name: door remotes (any) + name: steal-target-groups-door-remotes sprite: sprite: Objects/Devices/door_remote.rsi state: door_remotebase - type: stealTargetGroup id: EncryptionKey - name: encryption keys (any) + name: steal-target-groups-encryption-keys sprite: sprite: Objects/Devices/encryption_keys.rsi state: crypt_gray - type: stealTargetGroup id: TechnologyDisk - name: technology disks + name: steal-target-groups-technology-disks sprite: sprite: Objects/Misc/module.rsi state: datadisk_base - type: stealTargetGroup id: IDCard - name: ID Cards (any) + name: steal-target-groups-id-cards sprite: sprite: Objects/Misc/id_cards.rsi state: default - type: stealTargetGroup id: LAMP - name: LAMPS + name: steal-target-groups-lamps sprite: sprite: Objects/Tools/lantern.rsi state: lantern @@ -153,112 +153,112 @@ - type: stealTargetGroup id: ForensicScanner - name: forensic scanner + name: steal-target-groups-forensic-scanner sprite: sprite: Objects/Devices/forensic_scanner.rsi state: forensicnew - type: stealTargetGroup id: FlippoEngravedLighter - name: detective's Flippo engraved lighter + name: steal-target-groups-flippo-engraved-lighter sprite: sprite: Objects/Tools/lighters.rsi state: zippo_engraved_icon_base - type: stealTargetGroup id: AmmoTechFabCircuitboard - name: ammo techfab circuit board + name: steal-target-groups-ammo-tech-fab-circuitboard sprite: sprite: Objects/Misc/module.rsi state: security - type: stealTargetGroup id: ClothingHeadHatWarden - name: warden's cap + name: steal-target-groups-clothing-head-hat-warden sprite: sprite: Clothing/Head/Hats/warden.rsi state: icon - type: stealTargetGroup id: ClothingOuterHardsuitVoidParamed - name: paramedic void suit + name: steal-target-groups-clothing-outer-hardsuit-void-paramed sprite: sprite: Clothing/OuterClothing/Hardsuits/paramed.rsi state: icon - type: stealTargetGroup id: MedicalTechFabCircuitboard - name: medical techfab machine board + name: steal-target-groups-medical-tech-fab-circuitboard sprite: sprite: Objects/Misc/module.rsi state: medical - type: stealTargetGroup id: ClothingHeadsetAltMedical - name: chief medical officer's over-ear headset + name: steal-target-groups-clothing-headset-alt-medical sprite: sprite: Clothing/Ears/Headsets/medical.rsi state: icon_alt - type: stealTargetGroup id: ResearchAndDevelopmentServerMachineCircuitboard - name: R&D server machine board + name: steal-target-groups-research-and-development-server-machine-circuitboard sprite: sprite: Objects/Misc/module.rsi state: science - type: stealTargetGroup id: FireAxe - name: fireaxe + name: steal-target-groups-fire-axe sprite: sprite: Objects/Weapons/Melee/fireaxe.rsi state: icon - type: stealTargetGroup id: AmePartFlatpack - name: AME part + name: steal-target-groups-ame-part-flatpack sprite: sprite: Objects/Devices/flatpack.rsi state: ame-part - type: stealTargetGroup id: SalvageExpeditionsComputerCircuitboard - name: salvage expeditions computer board + name: steal-target-groups-salvage-expeditions-computer-circuitboard sprite: sprite: Objects/Misc/module.rsi state: cpu_supply - type: stealTargetGroup id: CargoShuttleConsoleCircuitboard - name: cargo shuttle console board + name: steal-target-groups-cargo-shuttle-console-circuitboard sprite: sprite: Objects/Misc/module.rsi state: cpuboard - type: stealTargetGroup id: ClothingEyesHudBeer - name: beer goggles + name: steal-target-groups-clothing-eyes-hud-beer sprite: sprite: Clothing/Eyes/Hud/beergoggles.rsi state: icon - type: stealTargetGroup id: Bible - name: bible + name: steal-target-groups-bible sprite: sprite: Objects/Specific/Chapel/bible.rsi state: icon - type: stealTargetGroup id: ClothingNeckGoldmedal - name: gold medal of crewmanship + name: steal-target-groups-clothing-neck-goldmedal sprite: sprite: Clothing/Neck/Medals/gold.rsi state: icon - type: stealTargetGroup id: ClothingNeckClownmedal - name: clown medal + name: steal-target-groups-clothing-neck-clownmedal sprite: sprite: Clothing/Neck/Medals/clownmedal.rsi state: icon @@ -267,70 +267,70 @@ - type: stealTargetGroup id: NuclearBomb - name: nuclear fission explosive + name: steal-target-groups-nuclear-bomb sprite: sprite: Objects/Devices/nuke.rsi state: nuclearbomb_base - type: stealTargetGroup id: FaxMachineCaptain - name: captain long range fax machine + name: steal-target-groups-fax-machine-captain sprite: sprite: Structures/Machines/fax_machine.rsi state: icon - type: stealTargetGroup id: ChemDispenser - name: chemical dispenser + name: steal-target-groups-chem-dispenser sprite: sprite: Structures/dispensers.rsi state: industrial-working - type: stealTargetGroup id: XenoArtifact - name: big alien artifact + name: steal-target-groups-xeno-artifact sprite: sprite: Objects/Specific/Xenoarchaeology/xeno_artifacts.rsi state: ano28 - type: stealTargetGroup id: FreezerHeater - name: freezer or heater + name: steal-target-groups-freezer-heater sprite: sprite: Structures/Piping/Atmospherics/thermomachine.rsi state: heaterOff - type: stealTargetGroup id: Teg - name: teg generator part + name: steal-target-groups-teg sprite: sprite: Structures/Power/Generation/teg.rsi state: teg - type: stealTargetGroup id: BoozeDispenser - name: booze dispenser + name: steal-target-groups-booze-dispenser sprite: sprite: Structures/smalldispensers.rsi state: booze - type: stealTargetGroup id: AltarNanotrasen - name: nanotrasen altar (any) + name: steal-target-groups-altar-nanotrasen sprite: sprite: Structures/Furniture/Altars/Gods/nanotrasen.rsi state: nanotrasen - type: stealTargetGroup id: PlantRD - name: RD's potted plant + name: steal-target-groups-plant-rd sprite: sprite: Structures/Furniture/potted_plants.rsi state: plant-25 - type: stealTargetGroup id: ToiletGoldenDirtyWater - name: golden toilet + name: steal-target-groups-toilet-golden-dirty-water sprite: sprite: Structures/Furniture/golden_toilet.rsi state: condisposal @@ -339,58 +339,56 @@ - type: stealTargetGroup id: AnimalIan - name: Ian + name: steal-target-groups-animal-ian sprite: sprite: Mobs/Pets/corgi.rsi state: ian - type: stealTargetGroup id: AnimalNamedCat - name: CMO's Cat + name: steal-target-groups-animal-named-cat sprite: sprite: Mobs/Pets/bingus.rsi state: bingus - type: stealTargetGroup id: AnimalMcGriff - name: McGriff + name: steal-target-groups-animal-mc-griff sprite: sprite: Mobs/Pets/mcgriff.rsi state: mcgriff - type: stealTargetGroup id: AnimalWalter - name: Walter + name: steal-target-groups-animal-walter sprite: sprite: Mobs/Pets/walter.rsi state: walter - type: stealTargetGroup id: AnimalMorty - name: Morty + name: steal-target-groups-animal-morty sprite: sprite: Mobs/Animals/possum.rsi state: possum - type: stealTargetGroup id: AnimalRenault - name: Renault + name: steal-target-groups-animal-renault sprite: sprite: Mobs/Animals/fox.rsi state: fox - type: stealTargetGroup id: AnimalShiva - name: Shiva + name: steal-target-groups-animal-shiva sprite: sprite: Mobs/Pets/shiva.rsi state: shiva - type: stealTargetGroup id: AnimalTropico - name: Tropico + name: steal-target-groups-animal-tropico sprite: sprite: Mobs/Animals/crab.rsi state: crab - - From 41617b9754f15ffaab3098910f9f2095ed451d0a Mon Sep 17 00:00:00 2001 From: Kanashi-Panda Date: Mon, 16 Sep 2024 17:35:57 -0700 Subject: [PATCH 085/138] Crayons buffed to 45 uses (#32061) * Buffs crayons to 45 uses * Update Resources/Prototypes/Entities/Objects/Fun/crayons.yml Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> --- Resources/Prototypes/Entities/Objects/Fun/crayons.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Prototypes/Entities/Objects/Fun/crayons.yml b/Resources/Prototypes/Entities/Objects/Fun/crayons.yml index ffecfdf9940..3c4a4800a87 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/crayons.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/crayons.yml @@ -21,7 +21,7 @@ enum.CrayonUiKey.Key: type: CrayonBoundUserInterface - type: Crayon - capacity: 15 + capacity: 25 - type: Food - type: FlavorProfile flavors: From 5eaac00432bdb4c7cdc255880666ea3490632f57 Mon Sep 17 00:00:00 2001 From: PJBot Date: Tue, 17 Sep 2024 00:37:05 +0000 Subject: [PATCH 086/138] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 27926b7a908..dd47739cb43 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Errant - changes: - - message: Vox now have their entry in the guidebook. - type: Fix - id: 6886 - time: '2024-07-09T00:28:33.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29713 - author: Whisper changes: - message: Light toggle actions now have a 1 second cooldown between uses. @@ -3910,3 +3903,10 @@ id: 7385 time: '2024-09-16T12:45:15.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/32147 +- author: Alice Liddel + changes: + - message: Crayon charges increased from 15 to 25 + type: Add + id: 7386 + time: '2024-09-17T00:35:57.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/32061 From 92be69a5abbaa358b1cdaaa34bb11076485ff685 Mon Sep 17 00:00:00 2001 From: Ed <96445749+TheShuEd@users.noreply.github.com> Date: Tue, 17 Sep 2024 12:49:19 +0300 Subject: [PATCH 087/138] Anomalous infections (#31876) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * inner anomaly * anomaly pulse action * test anom mine * Update anomalies.yml * fix action cooldown * pyro_eyes * clientsystem * experiments * blya * some telegraphy * shock eyes! * shadow eyes * separate files * frosty eyes * fix * flora eyes * bluespace eyes * flesh eyes * redoing injction * auto add layers * пипяу * new injector component * stupid me * nice marker injectors * anomaly spawn on shutdown * gravity anom * dead anomaly spawning * add VOX states * sprite specific layers support * technology anom infection * auto detach anomalies that have moved away * Update anomaly_injections.yml * anomalyspawner integration * rock anomaly! * Update anomaly_injections.yml * fix crash bug * tag filter * fix anom dublication spawns * Update anomaly.yml * Update InnerBodyAnomalyComponent.cs * Update anomaly_injections.yml * dont spawn anomalies after decay * fix morb sprite, add end message * gravity resprite * admin logging, double injection fix * make flesh and living light mobs friendly to anomaly hosts * popups * severity feedback * sloth review * A * keep organs after gib * punpun host * sloth synchronization * Update arachnid.yml * increase infections spawnrate --- .../Anomaly/Effects/ClientInnerBodySystem.cs | 50 ++ .../Anomaly/AnomalySynchronizerSystem.cs | 44 +- Content.Server/Anomaly/AnomalySystem.cs | 6 +- .../AnomalySynchronizerComponent.cs | 11 +- .../Anomaly/Effects/InnerBodyAnomalySystem.cs | 236 +++++++ .../Explosion/EntitySystems/TriggerSystem.cs | 3 +- .../Anomaly/Components/AnomalyComponent.cs | 15 +- .../Components/InnerBodyAnomalyComponent.cs | 72 ++ .../InnerBodyAnomalyInjectorComponent.cs | 21 + .../Effects/SharedInnerBodyAnomalySystem.cs | 5 + Content.Shared/Anomaly/SharedAnomalySystem.cs | 21 +- Resources/Audio/Effects/attributions.yml | 5 + Resources/Audio/Effects/inneranomaly.ogg | Bin 0 -> 46892 bytes .../Locale/en-US/anomaly/inner_anomaly.ftl | 17 + Resources/Prototypes/Actions/anomaly.yml | 9 + .../Markers/Spawners/Random/anomaly.yml | 31 +- .../Prototypes/Entities/Mobs/NPCs/animals.yml | 1 + .../Prototypes/Entities/Mobs/NPCs/flesh.yml | 7 +- .../Entities/Mobs/NPCs/living_light.yml | 5 + .../Prototypes/Entities/Mobs/NPCs/pets.yml | 1 + .../Entities/Mobs/Species/arachnid.yml | 1 + .../Prototypes/Entities/Mobs/Species/base.yml | 1 + .../Structures/Specific/Anomaly/anomalies.yml | 3 +- .../Specific/Anomaly/anomaly_injections.yml | 353 ++++++++++ .../Specific/Anomaly/anomaly_injectors.yml | 320 +++++++++ Resources/Prototypes/tags.yml | 3 + .../inner_anom_layer.rsi/bluespace.png | Bin 0 -> 864 bytes .../inner_anom_layer.rsi/bluespace_VOX.png | Bin 0 -> 1031 bytes .../Anomalies/inner_anom_layer.rsi/fire.png | Bin 0 -> 1007 bytes .../inner_anom_layer.rsi/fire_VOX.png | Bin 0 -> 1514 bytes .../Anomalies/inner_anom_layer.rsi/flesh.png | Bin 0 -> 1342 bytes .../inner_anom_layer.rsi/flesh_VOX.png | Bin 0 -> 1385 bytes .../Anomalies/inner_anom_layer.rsi/flora.png | Bin 0 -> 1868 bytes .../inner_anom_layer.rsi/flora_VOX.png | Bin 0 -> 1952 bytes .../Anomalies/inner_anom_layer.rsi/frost.png | Bin 0 -> 2650 bytes .../inner_anom_layer.rsi/frost_VOX.png | Bin 0 -> 2718 bytes .../Anomalies/inner_anom_layer.rsi/grav.png | Bin 0 -> 2837 bytes .../inner_anom_layer.rsi/grav_VOX.png | Bin 0 -> 3405 bytes .../Anomalies/inner_anom_layer.rsi/meta.json | 643 ++++++++++++++++++ .../Anomalies/inner_anom_layer.rsi/rock.png | Bin 0 -> 1398 bytes .../inner_anom_layer.rsi/rock_VOX.png | Bin 0 -> 1398 bytes .../Anomalies/inner_anom_layer.rsi/shadow.png | Bin 0 -> 768 bytes .../inner_anom_layer.rsi/shadow_VOX.png | Bin 0 -> 1002 bytes .../Anomalies/inner_anom_layer.rsi/shock.png | Bin 0 -> 879 bytes .../inner_anom_layer.rsi/shock_VOX.png | Bin 0 -> 2083 bytes .../Anomalies/inner_anom_layer.rsi/tech.png | Bin 0 -> 1241 bytes .../inner_anom_layer.rsi/tech_VOX.png | Bin 0 -> 1244 bytes .../Specific/anomaly.rsi/anom5-pulse.png | Bin 1195 -> 1252 bytes .../Structures/Specific/anomaly.rsi/anom5.png | Bin 429 -> 513 bytes 49 files changed, 1859 insertions(+), 25 deletions(-) create mode 100644 Content.Client/Anomaly/Effects/ClientInnerBodySystem.cs create mode 100644 Content.Server/Anomaly/Effects/InnerBodyAnomalySystem.cs create mode 100644 Content.Shared/Anomaly/Components/InnerBodyAnomalyComponent.cs create mode 100644 Content.Shared/Anomaly/Components/InnerBodyAnomalyInjectorComponent.cs create mode 100644 Content.Shared/Anomaly/Effects/SharedInnerBodyAnomalySystem.cs create mode 100644 Resources/Audio/Effects/inneranomaly.ogg create mode 100644 Resources/Locale/en-US/anomaly/inner_anomaly.ftl create mode 100644 Resources/Prototypes/Actions/anomaly.yml create mode 100644 Resources/Prototypes/Entities/Structures/Specific/Anomaly/anomaly_injections.yml create mode 100644 Resources/Prototypes/Entities/Structures/Specific/Anomaly/anomaly_injectors.yml create mode 100644 Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/bluespace.png create mode 100644 Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/bluespace_VOX.png create mode 100644 Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/fire.png create mode 100644 Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/fire_VOX.png create mode 100644 Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/flesh.png create mode 100644 Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/flesh_VOX.png create mode 100644 Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/flora.png create mode 100644 Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/flora_VOX.png create mode 100644 Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/frost.png create mode 100644 Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/frost_VOX.png create mode 100644 Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/grav.png create mode 100644 Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/grav_VOX.png create mode 100644 Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/meta.json create mode 100644 Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/rock.png create mode 100644 Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/rock_VOX.png create mode 100644 Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/shadow.png create mode 100644 Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/shadow_VOX.png create mode 100644 Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/shock.png create mode 100644 Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/shock_VOX.png create mode 100644 Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/tech.png create mode 100644 Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/tech_VOX.png diff --git a/Content.Client/Anomaly/Effects/ClientInnerBodySystem.cs b/Content.Client/Anomaly/Effects/ClientInnerBodySystem.cs new file mode 100644 index 00000000000..efb1a8d46e8 --- /dev/null +++ b/Content.Client/Anomaly/Effects/ClientInnerBodySystem.cs @@ -0,0 +1,50 @@ +using Content.Shared.Anomaly.Components; +using Content.Shared.Anomaly.Effects; +using Content.Shared.Body.Components; +using Robust.Client.GameObjects; + +namespace Content.Client.Anomaly.Effects; + +public sealed class ClientInnerBodyAnomalySystem : SharedInnerBodyAnomalySystem +{ + public override void Initialize() + { + SubscribeLocalEvent(OnAfterHandleState); + SubscribeLocalEvent(OnCompShutdown); + } + + private void OnAfterHandleState(Entity ent, ref AfterAutoHandleStateEvent args) + { + if (!TryComp(ent, out var sprite)) + return; + + if (ent.Comp.FallbackSprite is null) + return; + + if (!sprite.LayerMapTryGet(ent.Comp.LayerMap, out var index)) + index = sprite.LayerMapReserveBlank(ent.Comp.LayerMap); + + if (TryComp(ent, out var body) && + body.Prototype is not null && + ent.Comp.SpeciesSprites.TryGetValue(body.Prototype.Value, out var speciesSprite)) + { + sprite.LayerSetSprite(index, speciesSprite); + } + else + { + sprite.LayerSetSprite(index, ent.Comp.FallbackSprite); + } + + sprite.LayerSetVisible(index, true); + sprite.LayerSetShader(index, "unshaded"); + } + + private void OnCompShutdown(Entity ent, ref ComponentShutdown args) + { + if (!TryComp(ent, out var sprite)) + return; + + var index = sprite.LayerMapGet(ent.Comp.LayerMap); + sprite.LayerSetVisible(index, false); + } +} diff --git a/Content.Server/Anomaly/AnomalySynchronizerSystem.cs b/Content.Server/Anomaly/AnomalySynchronizerSystem.cs index 59ef08402ee..b1814c2741d 100644 --- a/Content.Server/Anomaly/AnomalySynchronizerSystem.cs +++ b/Content.Server/Anomaly/AnomalySynchronizerSystem.cs @@ -1,4 +1,5 @@ using System.Linq; +using System.Numerics; using Content.Server.Anomaly.Components; using Content.Server.DeviceLinking.Systems; using Content.Server.Power.Components; @@ -10,6 +11,7 @@ using Content.Shared.Power; using Robust.Shared.Audio.Systems; using Content.Shared.Verbs; +using Robust.Shared.Timing; namespace Content.Server.Anomaly; @@ -25,6 +27,7 @@ public sealed partial class AnomalySynchronizerSystem : EntitySystem [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly PowerReceiverSystem _power = default!; + [Dependency] private readonly IGameTiming _timing = default!; public override void Initialize() { @@ -40,6 +43,34 @@ public override void Initialize() SubscribeLocalEvent(OnAnomalyStabilityChanged); } + public override void Update(float frameTime) + { + base.Update(frameTime); + + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var sync, out var xform)) + { + if (sync.ConnectedAnomaly is null) + continue; + + if (_timing.CurTime < sync.NextCheckTime) + continue; + sync.NextCheckTime += sync.CheckFrequency; + + if (Transform(sync.ConnectedAnomaly.Value).MapUid != Transform(uid).MapUid) + { + DisconnectFromAnomaly((uid, sync), sync.ConnectedAnomaly.Value); + continue; + } + + if (!xform.Coordinates.TryDistance(EntityManager, Transform(sync.ConnectedAnomaly.Value).Coordinates, out var distance)) + continue; + + if (distance > sync.AttachRange) + DisconnectFromAnomaly((uid, sync), sync.ConnectedAnomaly.Value); + } + } + /// /// If powered, try to attach a nearby anomaly. /// @@ -73,10 +104,10 @@ private void OnPowerChanged(Entity ent, ref PowerC if (args.Powered) return; - if (!TryComp(ent.Comp.ConnectedAnomaly, out var anomaly)) + if (ent.Comp.ConnectedAnomaly is null) return; - DisconnectFromAnomaly(ent, anomaly); + DisconnectFromAnomaly(ent, ent.Comp.ConnectedAnomaly.Value); } private void OnExamined(Entity ent, ref ExaminedEvent args) @@ -125,13 +156,16 @@ private void ConnectToAnomaly(Entity ent, Entity ent, AnomalyComponent anomaly) + private void DisconnectFromAnomaly(Entity ent, EntityUid other) { if (ent.Comp.ConnectedAnomaly == null) return; - if (ent.Comp.PulseOnDisconnect) - _anomaly.DoAnomalyPulse(ent.Comp.ConnectedAnomaly.Value, anomaly); + if (TryComp(other, out var anomaly)) + { + if (ent.Comp.PulseOnDisconnect) + _anomaly.DoAnomalyPulse(ent.Comp.ConnectedAnomaly.Value, anomaly); + } _popup.PopupEntity(Loc.GetString("anomaly-sync-disconnected"), ent, PopupType.Large); _audio.PlayPvs(ent.Comp.ConnectedSound, ent); diff --git a/Content.Server/Anomaly/AnomalySystem.cs b/Content.Server/Anomaly/AnomalySystem.cs index 3e9760a056c..b0de3de8f3e 100644 --- a/Content.Server/Anomaly/AnomalySystem.cs +++ b/Content.Server/Anomaly/AnomalySystem.cs @@ -55,6 +55,7 @@ public override void Initialize() SubscribeLocalEvent(OnShutdown); SubscribeLocalEvent(OnStartCollide); + InitializeGenerator(); InitializeScanner(); InitializeVessel(); @@ -86,7 +87,10 @@ public void ShuffleParticlesEffect(Entity anomaly) private void OnShutdown(Entity anomaly, ref ComponentShutdown args) { - EndAnomaly(anomaly); + if (anomaly.Comp.CurrentBehavior is not null) + RemoveBehavior(anomaly, anomaly.Comp.CurrentBehavior.Value); + + EndAnomaly(anomaly, spawnCore: false); } private void OnStartCollide(Entity anomaly, ref StartCollideEvent args) diff --git a/Content.Server/Anomaly/Components/AnomalySynchronizerComponent.cs b/Content.Server/Anomaly/Components/AnomalySynchronizerComponent.cs index 235e740cf35..3127f091e55 100644 --- a/Content.Server/Anomaly/Components/AnomalySynchronizerComponent.cs +++ b/Content.Server/Anomaly/Components/AnomalySynchronizerComponent.cs @@ -7,7 +7,7 @@ namespace Content.Server.Anomaly.Components; /// /// a device that allows you to translate anomaly activity into multitool signals. /// -[RegisterComponent, Access(typeof(AnomalySynchronizerSystem))] +[RegisterComponent, AutoGenerateComponentPause, Access(typeof(AnomalySynchronizerSystem))] public sealed partial class AnomalySynchronizerComponent : Component { /// @@ -34,6 +34,15 @@ public sealed partial class AnomalySynchronizerComponent : Component [DataField] public float AttachRange = 0.4f; + /// + /// Periodicheski checks to see if the anomaly has moved to disconnect it. + /// + [DataField] + public TimeSpan CheckFrequency = TimeSpan.FromSeconds(1f); + + [DataField, AutoPausedField] + public TimeSpan NextCheckTime = TimeSpan.Zero; + [DataField] public ProtoId DecayingPort = "Decaying"; diff --git a/Content.Server/Anomaly/Effects/InnerBodyAnomalySystem.cs b/Content.Server/Anomaly/Effects/InnerBodyAnomalySystem.cs new file mode 100644 index 00000000000..38c4c51d874 --- /dev/null +++ b/Content.Server/Anomaly/Effects/InnerBodyAnomalySystem.cs @@ -0,0 +1,236 @@ +using Content.Server.Administration.Logs; +using Content.Server.Body.Systems; +using Content.Server.Chat.Managers; +using Content.Server.Jittering; +using Content.Server.Mind; +using Content.Server.Stunnable; +using Content.Shared.Actions; +using Content.Shared.Anomaly; +using Content.Shared.Anomaly.Components; +using Content.Shared.Anomaly.Effects; +using Content.Shared.Body.Components; +using Content.Shared.Chat; +using Content.Shared.Database; +using Content.Shared.Mobs; +using Content.Shared.Popups; +using Content.Shared.Whitelist; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Physics.Events; +using Robust.Shared.Prototypes; + +namespace Content.Server.Anomaly.Effects; + +public sealed class InnerBodyAnomalySystem : SharedInnerBodyAnomalySystem +{ + [Dependency] private readonly IAdminLogManager _adminLog = default!; + [Dependency] private readonly AnomalySystem _anomaly = default!; + [Dependency] private readonly ActionContainerSystem _actionContainer = default!; + [Dependency] private readonly SharedActionsSystem _actions = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly BodySystem _body = default!; + [Dependency] private readonly IChatManager _chat = default!; + [Dependency] private readonly EntityWhitelistSystem _whitelist = default!; + [Dependency] private readonly JitteringSystem _jitter = default!; + [Dependency] private readonly MindSystem _mind = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly IPrototypeManager _proto = default!; + [Dependency] private readonly StunSystem _stun = default!; + + private readonly Color _messageColor = Color.FromSrgb(new Color(201, 22, 94)); + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnStartCollideInjector); + + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnCompShutdown); + + SubscribeLocalEvent(OnAnomalyPulse); + SubscribeLocalEvent(OnAnomalyShutdown); + SubscribeLocalEvent(OnAnomalySupercritical); + SubscribeLocalEvent(OnSeverityChanged); + + SubscribeLocalEvent(OnMobStateChanged); + + SubscribeLocalEvent(OnActionPulse); + } + + private void OnActionPulse(Entity ent, ref ActionAnomalyPulseEvent args) + { + if (args.Handled) + return; + + _anomaly.DoAnomalyPulse(ent, ent.Comp); + + args.Handled = true; + } + + private void OnStartCollideInjector(Entity ent, ref StartCollideEvent args) + { + if (ent.Comp.Whitelist is not null && !_whitelist.IsValid(ent.Comp.Whitelist, args.OtherEntity)) + return; + if (TryComp(args.OtherEntity, out var innerAnom) && innerAnom.Injected) + return; + if (!_mind.TryGetMind(args.OtherEntity, out _, out var mindComponent)) + return; + + EntityManager.AddComponents(args.OtherEntity, ent.Comp.InjectionComponents); + QueueDel(ent); + } + + private void OnMapInit(Entity ent, ref MapInitEvent args) + { + AddAnomalyToBody(ent); + } + + private void AddAnomalyToBody(Entity ent) + { + if (!_proto.TryIndex(ent.Comp.InjectionProto, out var injectedAnom)) + return; + + if (ent.Comp.Injected) + return; + + ent.Comp.Injected = true; + + EntityManager.AddComponents(ent, injectedAnom.Components); + + _stun.TryParalyze(ent, TimeSpan.FromSeconds(ent.Comp.StunDuration), true); + _jitter.DoJitter(ent, TimeSpan.FromSeconds(ent.Comp.StunDuration), true); + + if (ent.Comp.StartSound is not null) + _audio.PlayPvs(ent.Comp.StartSound, ent); + + if (ent.Comp.StartMessage is not null && + _mind.TryGetMind(ent, out _, out var mindComponent) && + mindComponent.Session != null) + { + var message = Loc.GetString(ent.Comp.StartMessage); + var wrappedMessage = Loc.GetString("chat-manager-server-wrap-message", ("message", message)); + _chat.ChatMessageToOne(ChatChannel.Server, + message, + wrappedMessage, + default, + false, + mindComponent.Session.Channel, + _messageColor); + + _popup.PopupEntity(message, ent, ent, PopupType.MediumCaution); + + _adminLog.Add(LogType.Anomaly,LogImpact.Extreme,$"{ToPrettyString(ent)} became anomaly host."); + } + Dirty(ent); + } + + private void OnAnomalyPulse(Entity ent, ref AnomalyPulseEvent args) + { + _stun.TryParalyze(ent, TimeSpan.FromSeconds(ent.Comp.StunDuration / 2 * args.Severity), true); + _jitter.DoJitter(ent, TimeSpan.FromSeconds(ent.Comp.StunDuration / 2 * args.Severity), true); + } + + private void OnAnomalySupercritical(Entity ent, ref AnomalySupercriticalEvent args) + { + if (!TryComp(ent, out var body)) + return; + + _body.GibBody(ent, true, body, splatModifier: 5f); + } + + private void OnSeverityChanged(Entity ent, ref AnomalySeverityChangedEvent args) + { + if (!_mind.TryGetMind(ent, out _, out var mindComponent) || mindComponent.Session == null) + return; + + var message = string.Empty; + + if (args.Severity >= 0.5 && ent.Comp.LastSeverityInformed < 0.5) + { + ent.Comp.LastSeverityInformed = 0.5f; + message = Loc.GetString("inner-anomaly-severity-info-50"); + } + if (args.Severity >= 0.75 && ent.Comp.LastSeverityInformed < 0.75) + { + ent.Comp.LastSeverityInformed = 0.75f; + message = Loc.GetString("inner-anomaly-severity-info-75"); + } + if (args.Severity >= 0.9 && ent.Comp.LastSeverityInformed < 0.9) + { + ent.Comp.LastSeverityInformed = 0.9f; + message = Loc.GetString("inner-anomaly-severity-info-90"); + } + if (args.Severity >= 1 && ent.Comp.LastSeverityInformed < 1) + { + ent.Comp.LastSeverityInformed = 1f; + message = Loc.GetString("inner-anomaly-severity-info-100"); + } + + if (message == string.Empty) + return; + + var wrappedMessage = Loc.GetString("chat-manager-server-wrap-message", ("message", message)); + _chat.ChatMessageToOne(ChatChannel.Server, + message, + wrappedMessage, + default, + false, + mindComponent.Session.Channel, + _messageColor); + + _popup.PopupEntity(message, ent, ent, PopupType.MediumCaution); + } + + private void OnMobStateChanged(Entity ent, ref MobStateChangedEvent args) + { + if (args.NewMobState != MobState.Dead) + return; + + _anomaly.ChangeAnomalyHealth(ent, -2); //Shutdown it + } + + private void OnAnomalyShutdown(Entity ent, ref AnomalyShutdownEvent args) + { + RemoveAnomalyFromBody(ent); + RemCompDeferred(ent); + } + + private void OnCompShutdown(Entity ent, ref ComponentShutdown args) + { + RemoveAnomalyFromBody(ent); + } + + private void RemoveAnomalyFromBody(Entity ent) + { + if (!ent.Comp.Injected) + return; + + if (_proto.TryIndex(ent.Comp.InjectionProto, out var injectedAnom)) + EntityManager.RemoveComponents(ent, injectedAnom.Components); + + _stun.TryParalyze(ent, TimeSpan.FromSeconds(ent.Comp.StunDuration), true); + + if (ent.Comp.EndMessage is not null && + _mind.TryGetMind(ent, out _, out var mindComponent) && + mindComponent.Session != null) + { + var message = Loc.GetString(ent.Comp.EndMessage); + var wrappedMessage = Loc.GetString("chat-manager-server-wrap-message", ("message", message)); + _chat.ChatMessageToOne(ChatChannel.Server, + message, + wrappedMessage, + default, + false, + mindComponent.Session.Channel, + _messageColor); + + + _popup.PopupEntity(message, ent, ent, PopupType.MediumCaution); + + _adminLog.Add(LogType.Anomaly, LogImpact.Medium,$"{ToPrettyString(ent)} is no longer a host for the anomaly."); + } + + ent.Comp.Injected = false; + RemCompDeferred(ent); + } +} diff --git a/Content.Server/Explosion/EntitySystems/TriggerSystem.cs b/Content.Server/Explosion/EntitySystems/TriggerSystem.cs index 853b4fbc29d..57847551aa7 100644 --- a/Content.Server/Explosion/EntitySystems/TriggerSystem.cs +++ b/Content.Server/Explosion/EntitySystems/TriggerSystem.cs @@ -202,6 +202,7 @@ private void HandleGibTrigger(EntityUid uid, GibOnTriggerComponent component, Tr args.Handled = true; } + private void HandleRattleTrigger(EntityUid uid, RattleComponent component, TriggerEvent args) { if (!TryComp(uid, out var implanted)) @@ -230,7 +231,7 @@ private void HandleRattleTrigger(EntityUid uid, RattleComponent component, Trigg private void OnTriggerCollide(EntityUid uid, TriggerOnCollideComponent component, ref StartCollideEvent args) { if (args.OurFixtureId == component.FixtureID && (!component.IgnoreOtherNonHard || args.OtherFixture.Hard)) - Trigger(uid); + Trigger(uid, args.OtherEntity); } private void OnSpawnTriggered(EntityUid uid, TriggerOnSpawnComponent component, MapInitEvent args) diff --git a/Content.Shared/Anomaly/Components/AnomalyComponent.cs b/Content.Shared/Anomaly/Components/AnomalyComponent.cs index 724dfd38d2f..e6228b5fb0d 100644 --- a/Content.Shared/Anomaly/Components/AnomalyComponent.cs +++ b/Content.Shared/Anomaly/Components/AnomalyComponent.cs @@ -1,6 +1,6 @@ using System.Numerics; +using Content.Shared.Anomaly.Effects; using Content.Shared.Anomaly.Prototypes; -using Content.Shared.Damage; using Robust.Shared.Audio; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; @@ -16,7 +16,7 @@ namespace Content.Shared.Anomaly.Components; /// Anomalies and their related components were designed here: https://hackmd.io/@ss14-design/r1sQbkJOs /// [RegisterComponent, NetworkedComponent, AutoGenerateComponentState, AutoGenerateComponentPause] -[Access(typeof(SharedAnomalySystem))] +[Access(typeof(SharedAnomalySystem), typeof(SharedInnerBodyAnomalySystem))] public sealed partial class AnomalyComponent : Component { /// @@ -184,21 +184,21 @@ public sealed partial class AnomalyComponent : Component /// /// The minimum amount of research points generated per second /// - [DataField("minPointsPerSecond")] + [DataField] public int MinPointsPerSecond = 10; /// /// The maximum amount of research points generated per second /// This doesn't include the point bonus for being unstable. /// - [DataField("maxPointsPerSecond")] + [DataField] public int MaxPointsPerSecond = 70; /// /// The multiplier applied to the point value for the /// anomaly being above the /// - [DataField("growingPointMultiplier")] + [DataField] public float GrowingPointMultiplier = 1.5f; #endregion @@ -252,10 +252,13 @@ public sealed partial class AnomalyComponent : Component /// [ViewVariables(VVAccess.ReadWrite)] [DataField("offset")] - public Vector2 FloatingOffset = new(0, 0.15f); + public Vector2 FloatingOffset = new(0, 0); public readonly string AnimationKey = "anomalyfloat"; #endregion + + [DataField] + public bool DeleteEntity = true; } /// diff --git a/Content.Shared/Anomaly/Components/InnerBodyAnomalyComponent.cs b/Content.Shared/Anomaly/Components/InnerBodyAnomalyComponent.cs new file mode 100644 index 00000000000..e88cedb18ef --- /dev/null +++ b/Content.Shared/Anomaly/Components/InnerBodyAnomalyComponent.cs @@ -0,0 +1,72 @@ +using Content.Shared.Anomaly.Effects; +using Content.Shared.Body.Prototypes; +using Robust.Shared.Audio; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; +using Robust.Shared.Utility; + +namespace Content.Shared.Anomaly.Components; + +/// +/// An anomaly within the body of a living being. Controls the ability to return to the standard state. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true), Access(typeof(SharedInnerBodyAnomalySystem))] +public sealed partial class InnerBodyAnomalyComponent : Component +{ + [DataField] + public bool Injected; + + /// + /// A prototype of an entity whose components will be added to the anomaly host **AND** then removed at the right time + /// + [DataField(required: true)] + public EntProtoId? InjectionProto; + + /// + /// Duration of stun from the effect of the anomaly + /// + [DataField] + public float StunDuration = 4f; + + /// + /// A message sent in chat to a player who has become infected by an anomaly + /// + [DataField] + public LocId? StartMessage = null; + + /// + /// A message sent in chat to a player who has cleared an anomaly + /// + [DataField] + public LocId? EndMessage = "inner-anomaly-end-message"; + + /// + /// Sound, playing on becoming anomaly + /// + [DataField] + public SoundSpecifier? StartSound = new SoundPathSpecifier("/Audio/Effects/inneranomaly.ogg"); + + /// + /// Used to display messages to the player about their level of disease progression + /// + [DataField] + public float LastSeverityInformed = 0f; + + /// + /// The fallback sprite to be added on the original entity. Allows you to visually identify the feature and type of anomaly to other players + /// + [DataField, AutoNetworkedField] + public SpriteSpecifier? FallbackSprite = null; + + /// + /// Ability to use unique sprites for different body types + /// + [DataField, AutoNetworkedField] + public Dictionary, SpriteSpecifier> SpeciesSprites = new(); + + /// + /// The key of the entity layer into which the sprite will be inserted + /// + [DataField] + public string LayerMap = "inner_anomaly_layer"; +} diff --git a/Content.Shared/Anomaly/Components/InnerBodyAnomalyInjectorComponent.cs b/Content.Shared/Anomaly/Components/InnerBodyAnomalyInjectorComponent.cs new file mode 100644 index 00000000000..e4c398c9cc5 --- /dev/null +++ b/Content.Shared/Anomaly/Components/InnerBodyAnomalyInjectorComponent.cs @@ -0,0 +1,21 @@ +using Content.Shared.Anomaly.Effects; +using Content.Shared.Whitelist; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Anomaly.Components; + +/// +/// On contact with an entity, if it meets the conditions, it will transfer the specified components to it +/// +[RegisterComponent, Access(typeof(SharedInnerBodyAnomalySystem))] +public sealed partial class InnerBodyAnomalyInjectorComponent : Component +{ + [DataField] + public EntityWhitelist? Whitelist; + + /// + /// components that will be automatically removed after “curing” + /// + [DataField(required: true)] + public ComponentRegistry InjectionComponents = default!; +} diff --git a/Content.Shared/Anomaly/Effects/SharedInnerBodyAnomalySystem.cs b/Content.Shared/Anomaly/Effects/SharedInnerBodyAnomalySystem.cs new file mode 100644 index 00000000000..a1ec7cd3973 --- /dev/null +++ b/Content.Shared/Anomaly/Effects/SharedInnerBodyAnomalySystem.cs @@ -0,0 +1,5 @@ +namespace Content.Shared.Anomaly.Effects; + +public abstract class SharedInnerBodyAnomalySystem : EntitySystem +{ +} diff --git a/Content.Shared/Anomaly/SharedAnomalySystem.cs b/Content.Shared/Anomaly/SharedAnomalySystem.cs index c3d6591b725..9a0cde29988 100644 --- a/Content.Shared/Anomaly/SharedAnomalySystem.cs +++ b/Content.Shared/Anomaly/SharedAnomalySystem.cs @@ -1,13 +1,10 @@ using Content.Shared.Administration.Logs; using Content.Shared.Anomaly.Components; using Content.Shared.Anomaly.Prototypes; -using Content.Shared.Damage; using Content.Shared.Database; -using Content.Shared.Interaction; using Content.Shared.Physics; using Content.Shared.Popups; using Content.Shared.Weapons.Melee.Components; -using Content.Shared.Weapons.Melee.Events; using Robust.Shared.Audio.Systems; using Robust.Shared.Map; using Robust.Shared.Map.Components; @@ -21,6 +18,7 @@ using Robust.Shared.Utility; using System.Linq; using System.Numerics; +using Content.Shared.Actions; namespace Content.Shared.Anomaly; @@ -36,6 +34,7 @@ public abstract class SharedAnomalySystem : EntitySystem [Dependency] protected readonly SharedPopupSystem Popup = default!; [Dependency] private readonly IPrototypeManager _prototype = default!; [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly SharedTransformSystem _transform = default!; public override void Initialize() { @@ -145,7 +144,7 @@ public void DoAnomalySupercriticalEvent(EntityUid uid, AnomalyComponent? compone if (!Timing.IsFirstTimePredicted) return; - Audio.PlayPvs(component.SupercriticalSound, uid); + Audio.PlayPvs(component.SupercriticalSound, Transform(uid).Coordinates); if (_net.IsServer) Log.Info($"Raising supercritical event. Entity: {ToPrettyString(uid)}"); @@ -169,7 +168,8 @@ public void DoAnomalySupercriticalEvent(EntityUid uid, AnomalyComponent? compone /// The anomaly being shut down /// /// Whether or not the anomaly ended via supercritical event - public void EndAnomaly(EntityUid uid, AnomalyComponent? component = null, bool supercritical = false) + /// Create anomaly cores based on the result of completing an anomaly? + public void EndAnomaly(EntityUid uid, AnomalyComponent? component = null, bool supercritical = false, bool spawnCore = true) { // Logging before resolve, in case the anomaly has deleted itself. if (_net.IsServer) @@ -186,9 +186,14 @@ public void EndAnomaly(EntityUid uid, AnomalyComponent? component = null, bool s if (Terminating(uid) || _net.IsClient) return; - Spawn(supercritical ? component.CorePrototype : component.CoreInertPrototype, Transform(uid).Coordinates); + if (spawnCore) + { + var core = Spawn(supercritical ? component.CorePrototype : component.CoreInertPrototype, Transform(uid).Coordinates); + _transform.PlaceNextTo(core, uid); + } - QueueDel(uid); + if (component.DeleteEntity) + QueueDel(uid); } /// @@ -458,3 +463,5 @@ public partial record struct AnomalySpawnSettings() /// public bool SpawnOnSeverityChanged { get; set; } = false; } + +public sealed partial class ActionAnomalyPulseEvent : InstantActionEvent { } diff --git a/Resources/Audio/Effects/attributions.yml b/Resources/Audio/Effects/attributions.yml index 6f18510d17b..75cf22aa4fe 100644 --- a/Resources/Audio/Effects/attributions.yml +++ b/Resources/Audio/Effects/attributions.yml @@ -231,3 +231,8 @@ copyright: '"beep_landmine.ogg" by kaktuscsc of Discord for SS14' license: "CC-BY-SA-3.0" source: https://github.com/YuriyKiss/space-station-14/commit/971a135a9c83aed46e967aac9302ab5b35562b5f + +- files: [inneranomaly.ogg] + copyright: 'created by waveplaySFX on Freesound' + license: "CC0-1.0" + source: https://freesound.org/people/waveplaySFX/sounds/553744/ diff --git a/Resources/Audio/Effects/inneranomaly.ogg b/Resources/Audio/Effects/inneranomaly.ogg new file mode 100644 index 0000000000000000000000000000000000000000..43fc40357f2035e44587498af0aa886803b2ec5a GIT binary patch literal 46892 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 y?bC{%Tv^7p@8wU literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/fire.png b/Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/fire.png new file mode 100644 index 0000000000000000000000000000000000000000..a6fcde7a1841bc5fd50326ba2b168d9dd61b3735 GIT binary patch literal 1007 zcmeAS@N?(olHy`uVBq!ia0vp^3xK$RgAGXbBqvD&DaPU;cPEB*=VV?oFfgz5ba4!+ znDh3|`8?rpiDM718y`}20|$MvXa$f_HT ztu0qHoF;TkS&{kXNX4N9v3ZVRn^)RSHZJ{Cy+rxuD$D07O~;`8P)UU)7$gY^^Q-Pbn4h;Z~cb1Zec;bb*e_%i8pZ#HWxbgPO zZ@lvzmVV8@vp>*$?uEA5Z*x^Azl@)^w?rWR&ClnV2bev}RrgNZvdiO#(xJ6|Dw$6o zF0VkH6pl`SN?r^ZCme+l{Zwm^o;lo~66vwD<>? zpf{2KZ*1OoMNd6m_3Hon3H-qHKr$#;8T5^9+TGXg(fgL*EexUeY|or^M<=8yjFRx^0u06;x&Eo zpSG!2dic-tz4`ui-I9gNd|$ZS{Ca+N{1Mp=SF9Vtjl+UW>dH5X-^se`w|TBm=dF3%FOfK)$<=yo$Zr+m?ZDD-N-)sJ{ z{qnlcyi;QS@A>I!lCUWA`ubHZ-{tj9HZF1e^ReVE_t}{;cK=i~UzjHQ%I{wNGJW|^ zt)2fWKLd?TNwXCG5*7JvMNiGtKfh11V-Kg8%ropUO5ufK4=98a}O+?=Q>?{Ge`IO|BHAl mbki>yc5nDngUy`}_#DXiF)u5*PpgDXXhU z`~9TuAO4{Dz9)FzQQi-c2lkc-puAgU1^~opR>;dY9%at6yMn%=6vVk$Z$ahQC%+=! z420w*WHC$ZSnR>yB=qaZoCA_UqDK1N@i4B^5#qfcc3L!4p;}F$1gpc349))H%z6_D zjpK14sBz2httUER<3Btz@4@kLad9ZM-`7F!Ax0xrCZ z*Afv#O!o%}vzZ`Rz&NrWC2vGm(p`NZ0Prc|38QZ((N19zf-B^>`xo0nMhc{jAM@tI z9V9I=I{xz$)rRy$|`BDneVhp8PBf&XJ9UM{vJ7)X!7({L;h-TI)BI|^q{5n zppwmc%*odZk1tZ`H~KoUqb+3?pCl|%4mY(-98cLWDm94{slR{K&P^v~7>x&ip)i%C zo?W^6#$Pz7_VQlF?pp#`yh97ptb!NL>@@7PZ<`OD>U3KjMS#$SfuE&0fB+@eBwUS;7`I)ae*97>+Zb6bsbI}>e%6y2F3Qizw082T_(orZVMCcgMM zhs~@I)iKVv+Wa?h8GIR{4cUoL=H=K^sj%+7d_i}7 zoRo*XSYo|Qy-CZBt)AKv?Rfcy3hA(ijH)1VpE}wo=S5^D9H7-#)-BUsX!oua%aKYE zalPq6Peo|b*x0Pxt0tGe)+EX0-M-k_`MiAa+8f*^btQLO-^M&o&sY{^APj@oGHN!Y zU>6L*{^o$*hj)VXNe}LLY0d4jDuP%xLr+%~Y!0YdFKW_s>|`eTvDG01t^Zh~0H?lD zgE`qM14dM{ODkdKJLI;yD@u`QZT)9{LEZ5KA2 zji@pxWWE_&VePn<=|Ck)_WPzXzoeM}T!@kFWj>GrhwqS9L{vb&G-12$(pJH0mJ_s! zjEufM1G}PY2#=DSa4Ts8jwB6I;6%ie7=;uJ7Y!lgp(ju+=R!|=yAG+X%>CA?u z3EAy_=w|zUb{|mG3tdpVpS=Zj0KK||UCilbFl~z-NF=T7LrQO1f7hO&vS4wUd^mal q&t=oE!LUcCdT>8!{Hr!Cwk1g;k`7OgrHbr7Z@|g|jVwpp{^Kw7SjNf# literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/flesh.png b/Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/flesh.png new file mode 100644 index 0000000000000000000000000000000000000000..6e178307c33ea27caa13f9978a8337668a3eb2fe GIT binary patch literal 1342 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/flora.png b/Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/flora.png new file mode 100644 index 0000000000000000000000000000000000000000..70e369cb02ba37b76aea647060974a8a7517d27e GIT binary patch literal 1868 zcmZuxc{JOJ7WQfwr3TLsOO$3>wU**YDPsC8%~2FnM3FwNtudCWwUIDhE!9qF82d7% zRbiy4TGAw@53vNbH5H9iE7FQIB(?l1%gem?=j%P^-h0ly_uPB#_uX@gFZy|_s~V^( zC@84I&wB*Q{g7O9Rg~p6;$JZ+x%*pcp!Ye2&S~&R1%+>w;T}K!lv&4T!Tb&3dbDlY zNmV93xaf|uzWMC{Rqs=ArB?$kdfq61@mxXG>~Y7f!$l1*l5!!=$1Mn?AZCzRskxsW zcb%YeEFc_@hwydw5u=k#(pl2ke7wN>4#Z@IEnceb)#m7H$tNp}HL>Dv*BbKvNt#z3 zKZy+xVY}7YPT=!o{jup)_i&9vz#=y(v7=C4Qp`wOlC`8~8p+aIb&ev#3$d~T_JW|( zpbUy#@pv@LkjK1<85KmLWla()^{VUUZdft2u^sTg{tpg-Fuh$D z?yQE%-uJ;!kb_kTY)_cn2LrMPw;_;wtV=-lo^K-YlReaIW%U67twdfsW8g1wvBu6} z2grk!%k7?PL_-T$wdGwD8)kVlN3<93Ecitbw4h9fPciR&c>u zc!40&KL>`Q)G&S>HcpUZaF4b4SVWadE9G61<4gUO2)u4!d4C3n_n890X? zW!~zk9HE1Zt5a-hBG8U|)i_maGkRvDAj(p(&yHmI$hYwL?m>E$p^xsrXZuYhiJ@^) z&QH@{SW*5z*6x*UYb1JFhhgRp(klU`jNJTR9=2kiKqTz5%T@w@K2M4W=W76^6}q$T*=tp&o25MbQu4s;=}1L^E={u5w;>pZt`sA!=I9*8( z#h`Cy+ZQpqaTEEm54>E-DI(dcuG8J-jb57{_2-L(cxZ0pS``WFyQFf#x zd0qR;83RT`u*gINH~TZpHa=OZX!owcInau|8T4DY=x~eL)~a8isIWQ3I#eyjx{59s z>2089z0Lm_)1lr*pU?YTTHb>R`K8x{yT5!InrpXC-3nqq8cwe^rX+|aC!V#5kY28s zKlp+{Sv(g%Fa|{m4y2Rx45v>7VNYb=CfarF7*9QPH_s$n5!k>+MhZa^q9y1Uc4b(q zA|X0cx2THWpz;`tGBUTdzH67fCws`P#2nQH)@%YX3q|QPsfmMd9NCX%w{DgBQ)bX# zp?Bzo5Wt=rKgo8amJ2`d{Vd-&fs2SYUa#Q=)>KwJqVnYr*c4%`gqF&X;QE^5r1W?F z2v=PzmWHSD?K=-nouhn*7Oc5ggmNs{bvKOx$hb~t1P=Q=0WJR!K7Ljkw}z~49vLJr zk$e|{cqLTCU8*kMml@wa%{X0E5rClRcPL%<(SVObvA~#MH*98fXfXU=m(gTa zZQp)f0g4-OA$LFo&~Y%O`Sj-QWzCtC>c)km#%i{d{fUX0&-(5fcl!r6y<(9{sJyYb za4*Ba)EyK9fY_x4mV8{Do+|U{u?y#%OmUK4my_DUR*#sG+1vbn#0Y>TN`3leUjgQS zp|>ZN-h^r_*Z;;Cv|Ym^U+vsz)VP?W+?{$x6PfSs2DphvI%YmJYsulVM?UrFC+bw4 zpiT(0N=lIrja^|ou2qQ9iik)=&BVX#G5FWf-YfjmV##ud{NrY1E1Ggh zEx=BUW;6+Xs2W&bZXBQbU?tn#h%{JkoqHW|kGcA8VRT;%edf>E-EcF&O&B(z!N||| zg*gr1n+q4PuD-N1^_(8rE$_?I{!fZ$U|f~Vtw7x-VlhLSD*98cQBCvz(acqpDVj3p V!`4n{*8i1-d-{2Fp1bnPe*hXXv(*3q literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/flora_VOX.png b/Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/flora_VOX.png new file mode 100644 index 0000000000000000000000000000000000000000..97969116a97829de4c31cae8825cf0dd1f59e4b9 GIT binary patch literal 1952 zcmZvcdpr~R8^cWL@-d(^NN92LJ$? z@UzZdiuzV@Qq@!x8JHdsttd(fUT#hR+_3R70HAse?tI!ixq9sr(Zk4Z59!N--cBuR zCvRJ|^M`(W0_dze{oRwgY}-rfd;qBUK6%P5xT)g4LER~*c$Zcui=){;P!jJR z&$i9lvwSlII}c9Ykn||eZ#NwuM5QFHWA~Pf*P8B7dpO#fSk_=gEjbYl_ehx8}d0HeoEV7c4(|m5~-kvhN?l>@4 zr{DsN;pkXGobAEA9(rW}J)fc<&8f}IY$dIOi9vzK6c>%Ig*l-*4V%Q%fxQA(q3ebAg$VQd7EM!Pa4s;x)vKTOaluQeOap% zG5Of{EuDuCU|2?{JP8BRMjA8yW$plT41FSI5JtzyxU=O;-;bT1yi>8rrgDEjXg{3C zAPzsopk>ez`c*9Cz=6JX-~R+6m>cdMQ?gA6pWm(q+rrV>7ip;MgO?bPVqt7hRw62* zZPynzEavI8fNO=U`O3}N9{nOF2XA6TN>jF$R$Pcl63tLKJC^qM&-RZ3b1nODvE6!} zAS;}uVRy&+V1Gu~iOB5))nNL2M8HFh!;u8ECe^cDbeq2u8?%kFaIfCJ`tsA_>k*-X z&Gv#v(X8T)H|3F9r!m&g&ob;#0GIXS^W9rmTu5Oh>*DoKm`N;*Oskr0T8Ad1O%hT4 zvByJ+L93Ic1PGm3UIg4K`)N??8p9!Pu9-d~ivS_yqfAD^gK%T9j~SeRt71inEFavK z(j#V#oTu(Js^`9*Ng&gBfC1ClnN*~4?-3#K6|pi>nbj)iNlxssSwsTp*BPE~+xqwS zvd+NCj;a4D^UauBKGbY+rFfc{ZQ^biepQ$95U=-<+(Ir-iWEOywPb|*`U^wL607}8 zpaJ3boZwM!mEmg>4$Xgx6cQlitg?am%DX3GvfL>{jWLBq=CI4RnHsww&;+R{?DOa* z67Hqv&~_#_@blE08^5X2iziSo%%D3~b=Hu~44nV75>*17+BcSNhh>jmbT}s{)U{%*Jq6 z&VUsN=23RTKq&uUf38NpR^xh+%;gjy6z*2b5MmJTrTA@&p{)y>p=m`X3#&$+xCKx# zV?U}>JiX$bROeBAgBpCooSjj@1m_4C=J9T-o{h*6xavK!1Y>5D+^c|`!-aw1E@ZO4 zACAlW{2VM}8O53tC+z2qK&FVQ0FAD&y?21e>uwd{sbC!K6Dwo9BmZY}iUU+PD5IWl zP@(@=A%Qdr|EmlcA`%QvHWuVKISWegLy`@D>tVVD%_cn|fJHMbXcl41s)S+^O8G{g z8e06-)>ogiG+dFnAvbZdsoR9iY0g+^S5F*0{*Yy#kL(DDjo4Cc$o><(fRX}})x(zt zFr6aL5cxN0{!2JD^snbfuHbPhTl!X3xazB>3i|atcDd`==N2Piej||%1|7V2mq!^g z(AFk?R9nFT6H%^Rw;abM-4r(Tm8838Qxd!zt`Fmi^WeOkXVsEwMb_-KBU-pDl5Q3y z{%#sSDlk2)!+HGw^;lPn4k~6MuozlTJg-|)Z$3DgvJ07iY+Yh-3>L@tnU1?|(xSo< z+Qv-JMKuhOlRDvjx(G&~zV;#J?qSNLV^@>wNZ5bbn7GLK8MFb~qF1EobWzMF%_$il z6yjTym%geVt|OCCo8hWj8Ai9R5Y9g&cC7FGh&zt4pOuN*UzbM9`#MF6tsLd==EVry z)&HpGb^wzjp6tlK{$Zag|I$AIZ*P7_MX}tM3o_W0y{yXT7>Wf_?piE_8>}0I5v!HX qH5tEc(+}cesTp3SNWeEB+i$@B@T!;4Z2s{1N*nIt;f!+%zW+Z{QQd3+ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/frost.png b/Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/frost.png new file mode 100644 index 0000000000000000000000000000000000000000..4823cb5a6f2f7edd7a38ad837c42d8bec339c367 GIT binary patch literal 2650 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 Nz{1oDU4rt6{x604_oV;; literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/frost_VOX.png b/Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/frost_VOX.png new file mode 100644 index 0000000000000000000000000000000000000000..346cad09b1065c067a96bc22b9d2e6b2ee6d4764 GIT binary patch literal 2718 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 SQijm~5wNpyv?g16#{U!Z-Ghh# literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/meta.json b/Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/meta.json new file mode 100644 index 00000000000..4e069d0cd90 --- /dev/null +++ b/Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/meta.json @@ -0,0 +1,643 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Created by TheShuEd (github) for Space Station 14", + "states": [ + { + "name": "bluespace", + "directions": 4, + "delays": [ + [ + 0.3, + 0.3, + 0.3, + 0.3 + ], + [ + 0.3, + 0.3, + 0.3, + 0.3 + ], + [ + 0.3, + 0.3, + 0.3, + 0.3 + ], + [ + 0.3, + 0.3, + 0.3, + 0.3 + ] + ] + }, + { + "name": "bluespace_VOX", + "directions": 4, + "delays": [ + [ + 0.3, + 0.3, + 0.3, + 0.3 + ], + [ + 0.3, + 0.3, + 0.3, + 0.3 + ], + [ + 0.3, + 0.3, + 0.3, + 0.3 + ], + [ + 0.3, + 0.3, + 0.3, + 0.3 + ] + ] + }, + { + "name": "fire", + "directions": 4, + "delays": [ + [ + 0.2, + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2, + 0.2 + ] + ] + }, + { + "name": "fire_VOX", + "directions": 4, + "delays": [ + [ + 0.2, + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2, + 0.2 + ] + ] + }, + { + "name": "flesh", + "directions": 4, + "delays": [ + [ + 0.8, + 0.2, + 0.2 + ], + [ + 0.8, + 0.2, + 0.2 + ], + [ + 0.8, + 0.2, + 0.2 + ], + [ + 0.8, + 0.2, + 0.2 + ] + ] + }, + { + "name": "flesh_VOX", + "directions": 4, + "delays": [ + [ + 0.8, + 0.2, + 0.2 + ], + [ + 0.8, + 0.2, + 0.2 + ], + [ + 0.8, + 0.2, + 0.2 + ], + [ + 0.8, + 0.2, + 0.2 + ] + ] + }, + { + "name": "flora", + "directions": 4, + "delays": [ + [ + 0.3, + 0.3, + 0.3, + 0.3, + 0.3, + 0.3 + ], + [ + 0.3, + 0.3, + 0.3, + 0.3, + 0.3, + 0.3 + ], + [ + 0.3, + 0.3, + 0.3, + 0.3, + 0.3, + 0.3 + ], + [ + 0.3, + 0.3, + 0.3, + 0.3, + 0.3, + 0.3 + ] + ] + }, + { + "name": "flora_VOX", + "directions": 4, + "delays": [ + [ + 0.3, + 0.3, + 0.3, + 0.3, + 0.3, + 0.3 + ], + [ + 0.3, + 0.3, + 0.3, + 0.3, + 0.3, + 0.3 + ], + [ + 0.3, + 0.3, + 0.3, + 0.3, + 0.3, + 0.3 + ], + [ + 0.3, + 0.3, + 0.3, + 0.3, + 0.3, + 0.3 + ] + ] + }, + { + "name": "frost", + "directions": 4, + "delays": [ + [ + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2 + ] + ] + }, + { + "name": "frost_VOX", + "directions": 4, + "delays": [ + [ + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2 + ] + ] + }, + { + "name": "grav", + "directions": 4, + "delays": [ + [ + 0.3, + 0.3, + 0.3, + 0.3 + ], + [ + 0.3, + 0.3, + 0.3, + 0.3 + ], + [ + 0.3, + 0.3, + 0.3, + 0.3 + ], + [ + 0.3, + 0.3, + 0.3, + 0.3 + ] + ] + }, + { + "name": "grav_VOX", + "directions": 4, + "delays": [ + [ + 0.3, + 0.3, + 0.3, + 0.3 + ], + [ + 0.3, + 0.3, + 0.3, + 0.3 + ], + [ + 0.3, + 0.3, + 0.3, + 0.3 + ], + [ + 0.3, + 0.3, + 0.3, + 0.3 + ] + ] + }, + { + "name": "rock", + "directions": 4, + "delays": [ + [ + 0.9, + 0.2, + 0.2, + 0.2 + ], + [ + 0.9, + 0.2, + 0.2, + 0.2 + ], + [ + 0.9, + 0.2, + 0.2, + 0.2 + ], + [ + 0.9, + 0.2, + 0.2, + 0.2 + ] + ] + }, + { + "name": "rock_VOX", + "directions": 4, + "delays": [ + [ + 0.9, + 0.2, + 0.2, + 0.2 + ], + [ + 0.9, + 0.2, + 0.2, + 0.2 + ], + [ + 0.9, + 0.2, + 0.2, + 0.2 + ], + [ + 0.9, + 0.2, + 0.2, + 0.2 + ] + ] + }, + { + "name": "shadow", + "directions": 4, + "delays": [ + [ + 0.2, + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2, + 0.2 + ] + ] + }, + { + "name": "shadow_VOX", + "directions": 4, + "delays": [ + [ + 0.2, + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2, + 0.2 + ] + ] + }, + { + "name": "shock", + "directions": 4, + "delays": [ + [ + 0.2, + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2, + 0.2 + ] + ] + }, + { + "name": "shock_VOX", + "directions": 4, + "delays": [ + [ + 0.2, + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2, + 0.2 + ] + ] + }, + { + "name": "tech", + "directions": 4, + "delays": [ + [ + 0.2, + 0.4, + 0.2, + 0.4 + ], + [ + 0.2, + 0.4, + 0.2, + 0.4 + ], + [ + 0.2, + 0.4, + 0.2, + 0.4 + ], + [ + 0.2, + 0.4, + 0.2, + 0.4 + ] + ] + }, + { + "name": "tech_VOX", + "directions": 4, + "delays": [ + [ + 0.2, + 0.4, + 0.2, + 0.4 + ], + [ + 0.2, + 0.4, + 0.2, + 0.4 + ], + [ + 0.2, + 0.4, + 0.2, + 0.4 + ], + [ + 0.2, + 0.4, + 0.2, + 0.4 + ] + ] + } + ] +} diff --git a/Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/rock.png b/Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/rock.png new file mode 100644 index 0000000000000000000000000000000000000000..770e4b8d2f80570a23e6088fbc64afbe3fdeead7 GIT binary patch literal 1398 zcmZXUX;ji_6vintJvQQ2V`WMuEtV$1G>j3Eg(Btwb8FnvGDSr*mqdesHb>JOGc|L| zF>_0EU&at5b1PhqQfUxkDS1@TT=B00Lo=Uddd|7;bI$#A@43I{z3WK8X>0A&0)ar< zcss0<%5Qut&CRO!)ya!om2HT0!kq?H_U)Pkfz)AmthGx_u2gt5(CGYjjjxQex!Kpb z_X7@YHuNw^yM%JI!H-WS6#nqP%I+bRc9}5iXPYarqfUVnfwU%}9l}=k> z?Qk%7>JscoyVk)pixNC={3+4O$G_|0>cVfgSIBzf8lCtiQ)hxgIvbN|T^GBI+ zRTarFl5^6aazx#0l6p6yCI~I^W`xQ%1`D*I0au=llO+rg=U3<+=NhXWNznF?tzSiC zqT}FPMX*BEtt+#^chzldQFMOj2|M3Pk?5`1#wbI7Hva+mGD;Rxr-@y45B?zOw3vH{ zg};0eh|yMR{?x=*>vEUkm7_j9yAu_EoM@NurN}g!SNg)sQQ#W1Cm$9xj zhNbY@C{a$p~^arxpvFv96e~CO{pf`{eS@F15#n?|nwU!Q+ zNlY2~Xe2L~9WA#WhfJ&MeWU5+b;C;S7S6kov(>`g=LA6LYYm^UJeyAaMn40o9 zn$El(hEV>w>dL&+km;&JWlz=4^E=|vK1-tp?z1T*1$}+lK<__F4SSN+@|PjJHZMOa z@$-f5*U_p`>Eo1^t50J$M$?{Z07b?ju5a?_F1Q|p>cUsTgU=-eY`2E&D(_Yw;J}pm zQ8HiPWyKBMEA9r^*384C=D?w=dKD`oGg!_? m`JgawHNH#0KY<`*F+e(|1(%kpd*f9fDF|;vz*e62z4bREM%!Wl literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/rock_VOX.png b/Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/rock_VOX.png new file mode 100644 index 0000000000000000000000000000000000000000..b11a9182fb7fa91a8d13b392cbe6864f59a8633b GIT binary patch literal 1398 zcmZuxeK^wz9REpqsV8!Y%M`tMNmiQ5?Us!p#x)X&^V$pL5K}`N6Lqz`rRPe_%aJP; zTVaN6mP2USa+EBNoGq#`);6=Zn}6<}>$&gqe7~RP`#j&jKA-RBLkvKBuU~7i765?t zC?C&2EoQH@fu44D!DHB3&`AySMgnAxn_cKAGhy7XIug^LQxba!<;Rt7z?vZ4jY}iwyY$Sa zZgfWP4SaetAvzT^vVYfkBjMYWMshn$%=}3z-?B+inihLOEn-gSZ!kIF_=^v_0LDFC zec}!%trGQ^-&>zQ#*l?K{&qtP%Hd&6q1F44E<>H{h2lN6C23EaZi!DdJ+LKgPcj7Z zjj-1A_G?p@I?rb9kkI698|S5&h2|jHf?~?JBT?2o?cWWCz8flH(cXx}pK0I_jT&9I z+6C1iu5$Bpl_)UllGoY%5ig4oDtk%q9?8vdbdx4XC;XbDDZ4SiF;5ov@H+SzDWMnSrOwSy7`hi9N(`| z26f+I)!U%F5*`Le2lTw_XP6Q~O<<)ZVQchmQzA4eVh~h*Aj*(egOJsF<7lk!Ig(7sbFLSnyg)z3yxZf=+FXkW+0co zsK1JstCBQJ6}}y^CI2HF0{}m^FMH-Qb#g*pk>kHir`b$EC&T1aNW73VpOe)Sla=T| zNsr{|SHBjMrnUoL5OheCOV#zS3hkUW(e^yqUWiYdU_DQ+xBi4Uo;t(vHJar|k7}y8LczkS9(i}AhG8`_>Ur`ulBz)&E^ghGz zQDPWuB4c-Q)M}oDKC$7xZQSWS9Xl^K7vK=6b_#OdUF6CzTx3>VAwA5R_evg1tejDs z`quJQ+@GH`-RjCKP&ld1pkavEGt){tU3;?mla}-lrdlluiH);ukirudw}ir2JVh&3 zr9A8=$anyDR+Tot7Bhzgn+Fi_obLttpX#6+iC^)$vf_^>X5s`iG~A@Z*6!mjKd*!o z8eE@=X(_3AnMaq5_PrS0!;|P26Kdo-Tayr-+J_3C#Sz)#=F#o$C&lLsR|pB@?k=Y^ zgScrUnjVq2)A+B|nMxhTsAew74>GtDdH{N_3~|uX^%Y@0iGA=k;e_gWndjrHx&p!A z5QlPr|Qq0$M79#TFb@ZmIuh? z{F(?BR=x5X8gE>Wqi`8CKv9@Yn)%kgp35zAp#_WgO0hd)&kR?303N*rZM+0^lP#i8 zhT~g;ve^Kj=54==7d=ae2VTt{POQNT`MjV{Bk(1j9GtoMe7L7rN0$y(e4KsanQs1qDM5Q?@Tf)l+;e$W z_EDf9?6KozSwlOWO9z)HFfEM`s(QEPJo}l(1K(@?et92bv*%=B2>$$J;r$P-+i_Mt$A)E&TONAN%`r{$KiQcYXh92D6>BzsXNNbHA=?{_NYYzx|My^>^;xo45Vn zU;fsA-v5>1Z}aWfGk@>2=1;b*owUT#&VHr$x6fz4-oJlycIn&ik_TKTx!UeO_3+)n zub;zt^Or^8f#o&YZ~ppw9mBzaM8;ZH}pZcl4E2&&~b8p||7R zc>lFudaZFafA`YgwWXCz>sr6Dn4Epi{$K6C#G2F3-&uF;W#8~cc!h}h0TX+3U^o*1 zQ$8$tFTJO#Fhn(T|16cWule15?|;8K-|hcPhU^uSY`j0!e2wD$Fz=V}OMc6S(&?-` z7wbQNyjyeXuZZ3M+F#B*36oQ1K54)DI-~#pw*C7zn_KU-@Lu`v?AuZ=a8OM8`(?*J zXTAp@omcINS?qoFk3`#r5;NSh`e={pCe_wPte*Zt`a<>~V_P+RXef|AX z2J<3)tG^F_t+o|(mp`C(^3#_`I>(=@mvZH@hV7c)RIRwq`9DzTw{`Vq#b0yTHq48E zTJSv~yMr|+Y5#+`is1X*g|<`fb!NT#tC;)bTh2Bn?d%iM3obL*EwkRhjT)rE-}LV< Vp6pz5Th$HZG*4GQmvv4FO#q9YeJ=n2 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/shadow_VOX.png b/Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/shadow_VOX.png new file mode 100644 index 0000000000000000000000000000000000000000..6efb246ac1889f38de9d82fefbd4e0ce5b43fb5b GIT binary patch literal 1002 zcmeAS@N?(olHy`uVBq!ia0vp^3xK$RgAGXbBqvD&DaPU;cPEB*=VV?oFfcFiba4!+ znDh3|K`-f8iT01n=Poi4_#ni^%BsJx{9hgJ9b!|m(YAJ*^NE3~og;;b|C)~sByx^2qO`WN-DYAO!=+dt#sEuIR_EsuXY z>NG`!7>0((s?9c-X&V{5Vk1!5_pkP)b~XwB=bw*o;I`;reYC>(*ZlqUl1H*%O*uN} zpUbxr-_mOnjQ;QYxBOiFg@5OZ7?=%M;*OfC%=_iH{`A{eyIsrt63c5>-+ft{SaY1W z|Gb}tjjhtPkaXUM-}KV0=Kue;WZfSI9)ACR3p?w^!vE4|pU?YyKlXms`N_7g8P7Dn z-tj4r@$W&^-?OV%e-<%V%pmeUZhx+!9mCJ7XIZVKZ)a~@7RCSI-?MvJ^#vzW{vFSs ze@^oIl5@-x-sj}3kG&gnV8{Q<)j`>I1+w<<-~XL|qkq@;|I>A{|K_NySaRj7$z1!n z)2;q1rd2ZO^}J+jG0^#Y`;Sq?mh-MWc$VW&=q4t0J$@QN&cNhfa zJ7g*HX#algc6Zt*hGoxqKUCx~U=Nh~@7L=U;wH?j?$3L7chb}A+y19MW7a!#X0N;X z_q>yzvTy%4T5RdY`o((hy9O5H?-eb@@2Bb1v%WZfvwdpX^hzeS1uwqr`mNOVm|yQE&@*dyHB9;mOBE`!s>Rdq zEuB$4qv~DKtC`*1ieHbcTs|*;y1VhbvlHVpua+`Tv1>S8#XjvRuL6cI#7^v={PKP7 U5=RDMVCH4;boFyt=akR{0G7Mzr2qf` literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/shock.png b/Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/shock.png new file mode 100644 index 0000000000000000000000000000000000000000..acdc87a291c1f3ae96bef140d18330ebc0273608 GIT binary patch literal 879 zcmeAS@N?(olHy`uVBq!ia0vp^3xK$RgAGXbBqvD&DaPU;cPEB*=VV?oFfeO+x;TbZ z%z1mq-}`m~!|{*tk0u?Gc$1=k&HPfV+PhVgz1WrJZJWMSed3`m*V~^ZDsFtUi_-sU zBGIgNE4|(3;NOj#Onm1ptFsSC(th^a=4Em=znu^RL&1U5znCvBd3@(ehb6fN1s(~CvQpHKhJB|o0TWb39 zP4Df0%%A<&b?^Q+=kxhp43`~$Ov;<`NA1py->&|47jNWyzPI<>we4?q_5L6KR?N0L z`EP!$_5UZoU8{H8zmY%n!o0ilKmR(vnW1;m^t+|1`nz9$t9w{qf9JdZHr3o4|Jq76 zt-V;e{zK8?y{mu!{D19wh}E7=_w{e})XltJU-)+o_XUm0{qsG3X})Z?^?UQ!HNNHM z-(z*VEbe?My>?|qb!OXJN5zLv_MEQ%`~1yk%^7t|e*xnG8%U6I%{|EolzGs(>QsBr zsvco%s(@k%KPxN!1$?dU#XmPpe0$)D?fXsN&u*~&V7A-Zzw}@CtLIS-X79YCHa|C- z^iIY1^bU@7zmL6$mMM+f`D*vP|4P5=&KXvi$$721nQS$~sN&#{MekS1yU$%FbAJD; zzk9e1WLxxK?zWv~TIm@Sb3dE)Vf*=Yzlv=Bulg>&k)e0V$|cjkMcleCpK0IMw>{=d zbK!dV7WZ(Vyw>;6dI!GP+D|gsczpMo<`r4?>$aCYda>o@D*2x3>8pNxeI9J^*XujT zgIIvJ-sN)~>;7}k`}gYW|7yl{hvG`UOkY1gwRq8~_paMl)f(sU$9(%d$K>_92=C3} zbMFdY_!(DmaL4uXo6}YDH}8JDX}N3`BvB?| zym{v~rqm2EjUu<%Xp?RBd3&DkzpwB2Jm>t*bN)K#Jm+^#?%6Y^eVc$7&r^A1^Q^}R9R4_5{pm~o1@7P?7Z*F24ptx`Z2IgTK}w(G-)FmRUYrRpw^ zqOXC7ntOrEE7TzyB-lElFXGq-SAkP)n!o93LERX84MDS@b!N!x>N35re1;rd5OUA$ ziZhWqYC)c-_}0$oK@)evGWUme6YHGYR%9;a@;w6Ge2ZfM1mTYLfzbq?tSG{@RXEJJ z=#$FRDRNdM@D;8Vs&=ZPe0MNY$<*CWHq$c}Sn05PhiyohQO6^21ECDkn{$q3Sh=pj z771iN`c8002V(3q$yXc3uUkJgLus_Gm7~d)xSD!V-uEi|BJq4=Qq!ymNq$Tc;lJj8 zYtR2?OUoohu%pw{#nJGahc4KBZ+%w<*AB|W>Zeke2N8H527hD1Zb1P6nRbpnm)F@I za$KwY4cV&128N4LjLFlsk^h*=8jZ~$)WzjJf1qZGBH$ojR$uC9n@Ie~pXGvhQXxt4 ztp-~M&~zF48HMN6JyCS&eP*H`Z2wk~y{{j#2izZzw!ueW<(wr5?TNzW#tsU(9DWq= ztkaW|(y=k-OJAx638rs}=cFgto&uo~6?xEMOkxhlH#QX@(P&e$2*mIAosI1eXzm-5 zC0@WvS+F~y3^w*s{xV@B4d~^t>2w;?_>?dGplHOZ&>l!L$?vgF>MkGaH>$B(J%RPG5Rw5 zBqQ43Y;;r)bK_v2Cw^U?2Gde-zMx8#ot}4_HQrFmPJJogb(7Vu!FdBHziWojc}@PT zo4mX?*b6dkHo*@THO5g4c9`EjhqM`8>K@;pG1bgy$$}qIUFG@q;)t{`aq+*SV9K;u zIPf*KnN{cjs?dE-6bIUC+igT_xb?nWiV8$NiYy9}p4io*ec4oEnxX0D)$N+cPZ=kV zRZQlMrNn2g-{f;FrBse?XgMZ=GUWVpd_UaWtkdK zA;U1(j^fD<88^So1|Opn+^^g)^OVeX8rBI07hmfo-bvwoP-!E%91C`HwJkSSybEpm zAMsA00|I$x6ZWax^$4)hTSr5%J~|+7OEOvmhdji$Jy6KjS4{$G;GRA=tvc zTu=q*p<%tNhb3C2xCdrDsk@4q%BjxUlxA6{4NIDrT+PU-z1uFJ%c1FNk%G6BPvSrG z?0f&K6wT1xt83*wiZ86SD%s=XWk~K4cfTRnw&MXRE@OGnl4zNHnAf~-Cfw}GLKCZ8 zu3cmec1&IyV4SE9zwx@t;~#cx1xIUk2Q^DFrao!Xus>%|QD3IHt%!ueP7qD>Xb*NQ zyenWnlp=+@Ak#u=!k;JZKlC@{@lLQ&2vv8%+hahdV!J~WXSf!92*Soc6TjVkXe;|s z=Ag#$5s~+F!>{G_W=)(4jMB6uaxZ7uYmWo?*6NYILJkhn;#X}pnl zCY(wiwr(eh{)#tg>T|tP453L&Vo6(x>R61WkJ-}czOKSXUAa^tzgTOvX11($=9v5W z5)1slS1=d1RP!Vc3$k2_kw) zS_d3LE=U2LzszGkS|er8kJwND?ZZt{&L->GAxz`emsYx`)j&iCrG5@@`_^XA sbr(97leB9_@Ivj5`dR1SfWi{PkNB?&OTG2Bzdpd_#2M#$$AIhq0g=i0Q2+n{ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/tech.png b/Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/tech.png new file mode 100644 index 0000000000000000000000000000000000000000..0611fa8a2a092a82bedac5ee8b2aebd1d0ada50d GIT binary patch literal 1241 zcmZXTeN@tC6vwepo14;UGf&N6q`mD}*^A9UK*chbqG?8oP09?LE!+@w;@d_>OPiW2 z-z7}bFhwaa@C6l@PKKB-vGV;u87K)E7$Ue||8=%|&U5c`?{m+2p6ByD_qPz7zrEdN zI}iwDA8^bs6o^?L);b%&i_vE#K(L~O`ul*S!-8amt4EfjgRflA=7p zitRSv{1_AUSg@-n-1YfpsiZ{UVp^rgeoCMW96-`MqyqdJ=uIanKR#JF@U~Qglefq5 z!=fMNLi^d~zpA3^u~X&Cvs;MWS428~1G{V!?JPdn)+x;N-=5{+H6YSgKgBU{&wtAw3D97(mIFH?URS}35#X`cB%+@vU6s%>P7MCK!WLp+g z+FpgssbEChw%p(&YiJ;=sg&cKGD5c66#t-s%=UO4WG0v5r?`we#<7aV#l5hAs(e27x16hn$5{qv zaty>1qCToy>bg=)Vv1zWt-iMs28jHzb<*=mUWk(#VQz2jt?v<@%Ah_3aRZk>O3I1q zO`~5!jDuCHy4S*I21-F}UT>{Az0iK^&>?pLIqPN6W3pH3g%`>){h3pYAH{%?X=N(0vmiL=fySP_h7n)s{6~;_XHg-XU&7h`TR$b4MHL|0f07aAlm+8L3tgISw;e1MzTD zWl^jp5aPY1Th6lGWoqkioLecugD&bK4B^G|EOu#x;j^7(;g*r%`X!BHNOb~~MJsM0 zd58D+F;lINAtc{Lracm7S3}u#804O4s(Jt0*+{F7@t^OK(W`->LVK47<8tgRfKIY@ z03rh51n~&hYo?8hZydGxseQ;jwT#*qG94=aBb_+x}1X#z2n5J7s`;uP!k> zrY586fcZ#BywAp0<)coI;Jnc2ptWN+Eas()TV`U;hT4XhBLJ*`Q{l!C1Gho4Nwkra8tuP;DNxFNT(M uTtR_lur{mFm_)>RNY|n*`M-}($+fJ_Qq#-0ue^FboCO@g`8E0yfBhFxa%ye> literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/tech_VOX.png b/Resources/Textures/Structures/Specific/Anomalies/inner_anom_layer.rsi/tech_VOX.png new file mode 100644 index 0000000000000000000000000000000000000000..1787cdd4e06cebddb5753fbb349d2c06e2bcd10c GIT binary patch literal 1244 zcmZuwYfw@N6uy?Dt!D17Q){(+D0Fr0uw-hhF1l($_+S+W9|boj5#@Se@n5sEXXc#m%$z^x`@VBZqECjo zIBjg{N}mnvSg~P8fkp*t9sun5gplC)+)Dk#p$HTm)w8HU zO*IsKxnnBr^|UBFKDt>z&bTOd-{ZKSvymM-s&FUgoLhD9v;V#IWDvUR;_w$vPb*$| z|9rw;P~<(=LG;GdL$|&3v!Vg-7TJsKIhc$P_Smz2%jG&(Z7D7$!McVNOF8)!D=hjhko{vJXR(Ff znMa6aGma>YXl!Jp@b>&2B4LOyqDTS@^(0c|ytWu*C8rCj8!Wqh3RER+*9~`f`*E`2 zzr%+)??hhED1M$7& zP4p>ii8Hx*wIZr2{QBLi2j?)T_trEx2+KuaVx!fLgfF<>T4>wcIi=4}abm%UX>vj! zX1dT(!Y+Q~Mp);?(fAo3N@$cD@*JyrBG7M5AJ@jd(zf#TnSjpMBfs1*yTu*20;LG# z469U-b4&h6syB*EAJsBQmqhWPXeUA2aeN*;M>#b}ouF?k>!D>pnau;m(V5M!Y0L`K zy7bNuwzvkHal4XC>ap41_OpWUP}b=kAu}$6GA^&Q_*y^}SCiJ>q|QL7-kW>Js~(hD z;(Wty=!UiXTE3XTXmyhifuPK?NxSOkMl5D>^^61 z>&cs{;BDfYbX;!q&by{N@-9{DHwnlr3CQ|Ey2Z0@ngxpzmy_pQ_E5lKX(Zy=&_GOu zc+bUivLSzc(#LyVOo-PYHh@`N-d;LQZHmBYCLhAsn@QmMU_oL4l^eow!z6RIw&?lx z-TdlavtDQ<=Rkv*HBBs7J0dgQw{!KntXH*{nj6iSC7(ef`b;f=K`Jz7Y>>4rQFf0As+niKwk$uV>#8_aohnXjj?U7?CLJqb55M(Q( z_y7CNXy(nl2Nfz**km~C7LW(A=hXoDn*b9h3@3SPWpaQfc7K67uw@7s10x{HDO#z+LRm3xD|&_!sCqVK`d;bJxdjb%6H15BvuF1@OT=WDt>fea{KFi+u)>`Yu9x zW1mkXLjC~$0fH=}piKUsQZ%@zcg_>?Jts*1x#tA5_ha^)fTpWN^~OH!{g|VzAn7Ij z{0nU_3rgc(aDeuH12z0Egs?aEX}VK#AQ2(>eBDe$Xn$O2I}L63QIySZ8v)||1}N_f zp^4iYhua(V21!rIeR)npX7E)F$!w3xxI0?i+upAI1#0Bq3zYJ z4Gq|Ozaak9QDAd`M0k8~4-;~kb+3lqgdCU=BLd~S(F-+g_c6%Qw_7m(uC}}2fS*%D z%rxwc{eMJ6)9r9I?DBHE1MZY~5W%;HF3?do-02K$vzdY#D!jccnEw)ZW7A+80TS9K zHwHPVz1qJV1kP6PYUKg(RLR!*c>pHh99G^Gc&I_>wbIa zay9HGL?*dhjrCYIOshEH9u?ac$^Tv3UC99>RDT@(*1Ty>L^1?lH#$l0G+i}enah%f z#ORMkgF0A|c)m#fJ}|TeLpBFQOg9rrc-h{MlL<$>-8mT0IT*}{lnKc2zU&fb2W2`+ zm7eY|IV8-31DETbcK{Vt2kZiqQI{%Y) zgMTLGh@phtU=jRJIu8)c5tnuzPy~N;sCE7v3dzr(YkRK% zKlZ$Onj_X(A5cTZ_AOL|cLs&#=g+j=mgY$t32Unlki7gCo2mlx^Wp@6Ur66Lt$(dP zK=Sg(sIYd1yny^X+U_wadHOjWrPl{cP`%OzdRlCe`T2L+ZeQ~(b3pm^0ZtfBbhH!z z*QkxnsoC%e`T0|A?-~`5jM9RVwbuve2KV}b01C;^%LZxHJwa6;P$qv>ACUHssy?8q z57_V%p(R2#=S(m~$PQ{_BYOr3ay+idIovbyueUznN6QQ3O^wx=%M9h2>7N7grp6+s h`-fEvp({K`{11t~Wue8V+^PTo002ovPDHLkV1k!7P>BEl delta 1162 zcmV;51akqe~C0ep)b zBe&22Qsn|E45)UYSb*CIDkyaVRt?j5)+1_2&MwzB4D$g7jO8xh<8U2{<`u{jls&=&it)EAmRrAw||psYz}*j2P4eZ3w(Zj z=Q$10H^2HtpZL5Q0sxlv4wu6-0KnGO&t?c`j9Xc&=ARma%GxBqO5i=m>N#eOwODu&j3tH}TIW z*G+7QA!z`beSfn2crX&*qvzZR56E98IY0I9Yw)?-@T)w4&!#jB^xPNLmlyc`_!=Z` zEq~MizV%a(gynbv=ij=znPK1MIrrApt@x83z^ynQj6`xDTtu!H{4!Tq*1IP7UJlQi zzh%8^xJc9Hus_n6;{PZ;lq^Oa(hA^5eqY1}`=d7MvwzL1Fg506#qmL0TpQOj9*i(G z1_%U1(EucpL`zEzp8;+V-#~t!ZLqQyn0z^TzI8P=2YJwv#@K3*{0Yp~i<7~V2;j-( zd@)2mTQ5=+Nq!%j!@l_$q~g z>*^%GYJVB@XMse-1}}Zr6}%ss{kGqQkTk#rP<_U+C@6TdaK>cqMBn{RFxvpRGtdWjj)u+#xPJ#67x2=DB7e|bjS#&QmB7#A^TE@V z^$fPt-G5uqKq+BLxLGfnHqAu{LH(jnEZxW~>m7dByXGpYjgU6{Kh2ex5Ad(Tdb<(g z`FW{6fD52@ZGOHjzh57~LC>G1K7hzChi6Srzz44%nD_6jSXrwkrv&PG zHGjm)+Uy%6ntfg$km3f=@TY>K$^*DHV<~DPmcGk@-%qGW!=EG#f2;Zco)PxTVnTv) z>I3}Q=lzDz)(fHrm>SbuJyTMGTR#+tIBqA`ssx1(5*_nCDNz#gf{+n{2H+p?0tKl+ z$`>OUM!QjQ#yII+J^|GK=CD68Ld+wjzJG%op~~9I8RN9cNM5KQ6;EiFLwb*dh6*6~ zPw;$rJSm|VA!&$;q8RY^(^s)QR;WO2-|b!JBq_y!-vNH$sR~3Y(g1*O|Ncbx1D)#w z_~0cEIj@Gm09hGg^1`{mPa1&JlAL9|!v_1NJSOISs%7vdQKix5yDkXz!@ZB|Ab(vN zepP+I)R?1Sqe)Y5U5%+R*$1P_+7o`RAyg(q{Jm|3d44_>7-=uwC%V)JXwd02_%l); z(DpReg`W;(u_9?L|C_51h}{QtF??2i0N>%QtbNh^ytG;B)8n#)yd-yM=lE_=uEh%q c3Ucrt#86llirPac00000NkvXXt^-0~f~LST$1WzK;UIe|0kXP`*_q4B25Mgfx zFD)XTgceHnkexIYZEJR6Fa2+6ll$fG)dl@|ixL>$h8&_}=t={D5P2Pf(0#h6keJ23eI*_WD&HZB$(|gJJ z54nn8ehZ-e9ssR2^w0iJ0DK5&zlOe=HvHq)unz>njDr9kfrJ{58Z}Dv4O?Og7Rhkr QfdBvi07*qoM6N<$g2@Wm4FCWD delta 389 zcmV;00eb#{1g!&*F@I-CL_t(oh3%FxZiFxpML!_|87alG1vkiQ%RRszf|GIx4nWBn zkOFidBO#|6WV|*WP*!R9rLq0rAI1jY)TvYdtl;RvTnJ^372~*jzugPSxSMA@uMafS zfGkQ-wiVJa+zrB>Xd0(M3;?KQk9&Lp0CY<324Ml@LMSsa0e=t#04s2W(ixTTR8rLDZdA2s|E&u?lG-i5z+=Sy)VG}@4&yhKg zQw47Y^b}c?pqBkoW|ul8t?O<2^Z}5_lum%z`TCq@8qi=^J#&fG19aB!@ntEqe&kF* zjxigcY%A-AWPaRC!%KAtu$Dc_w%Xi(^A!~18012zPRW-BYo=i_aw&@v{CF-S)+;bm zPM#W)6O7_K_InfwjbDfzcoaoJWY2%kA8J#g@A`2BTrHs)KthAt5Ol6m|8 jfD1&|kw2nSr%wF>39-#Z{0ZNi00000NkvXXu0mjfSD&j} From 21bd9df4775144d429c741ac54b5d373b3675cb9 Mon Sep 17 00:00:00 2001 From: PJBot Date: Tue, 17 Sep 2024 09:50:26 +0000 Subject: [PATCH 088/138] Automatic changelog update --- Resources/Changelog/Changelog.yml | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index dd47739cb43..cc6d0ca3e05 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Whisper - changes: - - message: Light toggle actions now have a 1 second cooldown between uses. - type: Tweak - id: 6887 - time: '2024-07-09T04:14:51.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29833 - author: Cojoke-dot changes: - message: Shotgun loading doafter now does something @@ -3910,3 +3903,18 @@ id: 7386 time: '2024-09-17T00:35:57.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/32061 +- author: TheShuEd + changes: + - message: Anomalous infections added! People can now be infected by anomalies! + This allows you to use abnormal abilities, but can easily kill the host. To + cure them, bombard them with containment particles, because if the anomaly inside + them explodes, their bodies will be gibbed.... + type: Add + - message: Flesh anomaly resprite + type: Tweak + - message: anomalies now disconnect from the anomaly synchronizer if they are too + far away from it. + type: Fix + id: 7387 + time: '2024-09-17T09:49:19.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/31876 From dce537df071f899f8419e512bd38991ee2a39771 Mon Sep 17 00:00:00 2001 From: Ed <96445749+TheShuEd@users.noreply.github.com> Date: Tue, 17 Sep 2024 19:05:38 +0300 Subject: [PATCH 089/138] fix Tech anomaly loud sounds and superfast flickering (#32245) Update TechAnomalySystem.cs --- Content.Server/Anomaly/Effects/TechAnomalySystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Server/Anomaly/Effects/TechAnomalySystem.cs b/Content.Server/Anomaly/Effects/TechAnomalySystem.cs index 1b2849f1d77..3e4d101f4fd 100644 --- a/Content.Server/Anomaly/Effects/TechAnomalySystem.cs +++ b/Content.Server/Anomaly/Effects/TechAnomalySystem.cs @@ -37,7 +37,7 @@ public override void Update(float frameTime) if (_timing.CurTime < tech.NextTimer) continue; - tech.NextTimer += TimeSpan.FromSeconds(tech.TimerFrequency * anom.Stability); + tech.NextTimer += TimeSpan.FromSeconds(tech.TimerFrequency); _signal.InvokePort(uid, tech.TimerPort); } From 9afc786573fa1e9a7077eac17aeb0f00c4000cad Mon Sep 17 00:00:00 2001 From: PJBot Date: Tue, 17 Sep 2024 16:06:45 +0000 Subject: [PATCH 090/138] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index cc6d0ca3e05..edca864463e 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Cojoke-dot - changes: - - message: Shotgun loading doafter now does something - type: Fix - id: 6888 - time: '2024-07-09T04:23:08.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29827 - author: slarticodefast changes: - message: The construction menu and building preview now show the correct passive @@ -3918,3 +3911,10 @@ id: 7387 time: '2024-09-17T09:49:19.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/31876 +- author: TheShuEd + changes: + - message: fix Tech anomaly loud sounds and superfast flickering + type: Fix + id: 7388 + time: '2024-09-17T16:05:38.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/32245 From 337af483ca0922050459dcd8e8955c2775387526 Mon Sep 17 00:00:00 2001 From: drakewill-CRL <46307022+drakewill-CRL@users.noreply.github.com> Date: Tue, 17 Sep 2024 15:45:42 -0400 Subject: [PATCH 091/138] Fix plant mutations carrying over to other plants and future rounds (#32257) Lists are a reference type, so each component should get a new one, not point at the previous one. Co-authored-by: PraxisMapper --- Content.Server/Botany/SeedPrototype.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Content.Server/Botany/SeedPrototype.cs b/Content.Server/Botany/SeedPrototype.cs index 7a3e08883de..5608338f22e 100644 --- a/Content.Server/Botany/SeedPrototype.cs +++ b/Content.Server/Botany/SeedPrototype.cs @@ -291,12 +291,13 @@ public SeedData Clone() CanScream = CanScream, TurnIntoKudzu = TurnIntoKudzu, SplatPrototype = SplatPrototype, - Mutations = Mutations, + Mutations = new List(), // Newly cloned seed is unique. No need to unnecessarily clone if repeatedly modified. Unique = true, }; + newSeed.Mutations.AddRange(Mutations); return newSeed; } From 60887dd2e5c6e665503cbf1784ae3bb0a3289b05 Mon Sep 17 00:00:00 2001 From: PJBot Date: Tue, 17 Sep 2024 19:46:48 +0000 Subject: [PATCH 092/138] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index edca864463e..445dae8c988 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: slarticodefast - changes: - - message: The construction menu and building preview now show the correct passive - vent sprite. - type: Fix - id: 6889 - time: '2024-07-09T13:39:47.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29820 - author: Cojoke-dot changes: - message: Pacifists can now use foam weaponry @@ -3918,3 +3910,10 @@ id: 7388 time: '2024-09-17T16:05:38.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/32245 +- author: drakewill-CRL + changes: + - message: Fixed plant mutations carrying over to other plants and future rounds. + type: Fix + id: 7389 + time: '2024-09-17T19:45:42.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/32257 From 6fc4e9682c8c4e38a38cfa03bd04fe7e5b5c3e28 Mon Sep 17 00:00:00 2001 From: Moomoobeef <62638182+Moomoobeef@users.noreply.github.com> Date: Tue, 17 Sep 2024 15:09:55 -0700 Subject: [PATCH 093/138] Added a number of new and very nerdy names for the AI (#31951) * added many new names for AIs * fixed mistakes * removed Intel and AMD trademarks. Rip AI named Pentium. --- Resources/Prototypes/Datasets/Names/ai.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Resources/Prototypes/Datasets/Names/ai.yml b/Resources/Prototypes/Datasets/Names/ai.yml index 1d320c3f52f..539ef4e3fad 100644 --- a/Resources/Prototypes/Datasets/Names/ai.yml +++ b/Resources/Prototypes/Datasets/Names/ai.yml @@ -2,8 +2,11 @@ id: names_ai values: - 16-20 + - 512k + - 640k #ought to be enough for anybody - "790" - Adaptive Manipulator + - Adlib #named after the famous soundcard - ALICE - Allied Mastercomputer - Alpha 2 @@ -19,21 +22,28 @@ - Aniel - AOL - Asimov + - Bell 301 #the most influential modem ever, created by the bell system. It still lives on today in certain applications - Bishop - Blitz - Box + - Calculator - Cassandra - Cell - Chii - Chip + - C.R.A.I.G. + - Cray-2 #commercial supercomputer from the 70s + - CompuServe #if we're going to have AOL we may as well have some of their major competitors - Computer - Cutie - Daedalus + - DecTalk - Dee Model - Dial Up - Dorfl - Duey - Emma-2 + - ENIAC #famous early computer - Erasmus - Everything - Ez-27 @@ -47,12 +57,16 @@ - Helios - Hivebot Overmind - Huey + - iAI #a play on the fad apple spawned of putting "i" infront of your tech products name + - I.E. 6 #hell on earth (web browser) - Icarus + - Jeeves #if you don't get this one you are too young - Jinx - K.I.N.G - Klapaucius - Knight - Louie + - Manchester Mark 2 #named after the Manchester Mark 1, the successor of which was actually named the Ferranti Mark 1, rather than Manchester Mark 2 - MARK13 - Maria - Marvin @@ -64,6 +78,8 @@ - Mugsy3000 - Multivac - NCH + - NT v6.0 #A play on both NT as in NanoTrasen and NT as in windows NT, of which version 6.0 is windows vista + - Packard Bell - PTO - Project Y2K - Revelation @@ -76,10 +92,13 @@ - Shrike - Solo - Station Control Program + - AINU (AI's Not Unix) - Super 35 - Surgeon General - TWA - Terminus + - TPM 3.0 + - Turing Complete - Tidy - Ulysses - W1k1 From 870bacbcacedb7be7be95c9849470c7c4bf05e41 Mon Sep 17 00:00:00 2001 From: PJBot Date: Tue, 17 Sep 2024 22:11:01 +0000 Subject: [PATCH 094/138] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 445dae8c988..11609a0efc9 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Cojoke-dot - changes: - - message: Pacifists can now use foam weaponry - type: Tweak - id: 6890 - time: '2024-07-09T13:46:21.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29835 - author: Plykiya changes: - message: You can now drop food and drinks to stop consuming it. @@ -3917,3 +3910,10 @@ id: 7389 time: '2024-09-17T19:45:42.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/32257 +- author: Moomoobeef + changes: + - message: Added more names to the pool of names the AI can have. + type: Add + id: 7390 + time: '2024-09-17T22:09:55.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/31951 From 61089355f047da92b8e2e19c70a26fbd73715d60 Mon Sep 17 00:00:00 2001 From: Ed <96445749+TheShuEd@users.noreply.github.com> Date: Wed, 18 Sep 2024 01:19:34 +0300 Subject: [PATCH 095/138] Fix Anomaly infections infinity growing after curing (#32259) --- Content.Client/Anomaly/AnomalySystem.cs | 12 +++++++++++- Content.Shared/Anomaly/SharedAnomalySystem.cs | 2 ++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Content.Client/Anomaly/AnomalySystem.cs b/Content.Client/Anomaly/AnomalySystem.cs index c93f0ce9490..28c015f3021 100644 --- a/Content.Client/Anomaly/AnomalySystem.cs +++ b/Content.Client/Anomaly/AnomalySystem.cs @@ -20,8 +20,9 @@ public override void Initialize() SubscribeLocalEvent(OnAppearanceChanged); SubscribeLocalEvent(OnStartup); SubscribeLocalEvent(OnAnimationComplete); - } + SubscribeLocalEvent(OnShutdown); + } private void OnStartup(EntityUid uid, AnomalyComponent component, ComponentStartup args) { _floating.FloatAnimation(uid, component.FloatingOffset, component.AnimationKey, component.AnimationTime); @@ -75,4 +76,13 @@ public override void Update(float frameTime) } } } + + private void OnShutdown(Entity ent, ref ComponentShutdown args) + { + if (!TryComp(ent, out var sprite)) + return; + + sprite.Scale = Vector2.One; + sprite.Color = sprite.Color.WithAlpha(1f); + } } diff --git a/Content.Shared/Anomaly/SharedAnomalySystem.cs b/Content.Shared/Anomaly/SharedAnomalySystem.cs index 9a0cde29988..07beb1444d7 100644 --- a/Content.Shared/Anomaly/SharedAnomalySystem.cs +++ b/Content.Shared/Anomaly/SharedAnomalySystem.cs @@ -194,6 +194,8 @@ public void EndAnomaly(EntityUid uid, AnomalyComponent? component = null, bool s if (component.DeleteEntity) QueueDel(uid); + else + RemCompDeferred(uid); } /// From eca63a460393cea0fe7b6d1a24402ce9cf840b86 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Wed, 18 Sep 2024 03:40:24 +0200 Subject: [PATCH 096/138] Fix borg defib module throwing an exception (#32260) ToggleCellDraw was erroneously added to the parent prototype instead of the one that actually has a battery. --- .../Prototypes/Entities/Objects/Specific/Medical/defib.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Prototypes/Entities/Objects/Specific/Medical/defib.yml b/Resources/Prototypes/Entities/Objects/Specific/Medical/defib.yml index 7b5ba23fe33..69c106efab1 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Medical/defib.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Medical/defib.yml @@ -47,13 +47,13 @@ - type: GuideHelp guides: - Medical Doctor - - type: ToggleCellDraw - type: entity id: Defibrillator parent: [ BaseDefibrillator, PowerCellSlotMediumItem ] components: - type: MultiHandedItem + - type: ToggleCellDraw - type: PowerCellDraw useRate: 100 From 675a9197f20ee467c0fc99a03efccce47785186f Mon Sep 17 00:00:00 2001 From: Ed <96445749+TheShuEd@users.noreply.github.com> Date: Wed, 18 Sep 2024 04:41:24 +0300 Subject: [PATCH 097/138] Easy IconSmooth spriting (#32210) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * фыр * Update IconSmoothingTemplate README.txt --- .../IconSmoothingTemplate README.txt | 4 ++++ .../IconSmoothingTemplate.aseprite | Bin 0 -> 14094 bytes 2 files changed, 4 insertions(+) create mode 100644 Tools/SS14 Aseprite Templates/IconSmoothingTemplate README.txt create mode 100644 Tools/SS14 Aseprite Templates/IconSmoothingTemplate.aseprite diff --git a/Tools/SS14 Aseprite Templates/IconSmoothingTemplate README.txt b/Tools/SS14 Aseprite Templates/IconSmoothingTemplate README.txt new file mode 100644 index 00000000000..083e803ecd1 --- /dev/null +++ b/Tools/SS14 Aseprite Templates/IconSmoothingTemplate README.txt @@ -0,0 +1,4 @@ +This is a template that greatly simplifies working with IconSmooth sprites. + +A video on how to use it can be found at the link: +https://github.com/space-wizards/space-station-14/pull/32210 \ No newline at end of file diff --git a/Tools/SS14 Aseprite Templates/IconSmoothingTemplate.aseprite b/Tools/SS14 Aseprite Templates/IconSmoothingTemplate.aseprite new file mode 100644 index 0000000000000000000000000000000000000000..112a1d932cadd62741abd5abceda653934e920fa GIT binary patch literal 14094 zcmeHNc~}$4wr^#;%!~_;Gwy?c=(r#vf`YQd8L#5#RYXKUgp48vMa;M$OCZhoMnzPj zBH{*75El?4AcifpiVzhvB1;4$jVuNU5JE^gNvFGR13K3?-~HqLao@Y&{T`LCI+d=| zr%s(Z=U3-+YMdPeHK&b$ppiPr6r#SNomBltv4=(s+@$(U|8etQ*os>UK{`dm;HVK4 z-$_(8G#woBvr%%W_7?-v*$eL;$vL|D`1<8LY;D)fUKC_L@8-<8VwaikBW*#;Zh78! zGC$~=lbOBE()=s?js>pwSm_k$v9K)4Fg$nB;$ti4`)#sVwQV6I>Z{8Mi%Nbw*$C%X zzKKaK_S+w~+GWRL8~64z1(~}_SZi*sbKdQ+=D<$}vive+_d3-Yji#pN^_lpKzP>w` z*g0?X*cN%@_|1&FMPdHF-K9qLoE-s{bnP~dUV#D-#p>aHyfH_;~G*511V7^G#{$H zL*603oIKL*i=M{m^hiaBOooZAU^hb3Uv<}z(?BmnVC)@oKeFQV^A3do1cg6iPQY`Q zUi1aGyVEf+)^X2tV~{XgflfWy+g+3=*@BBy`3blDWc>9_f&|P~ z&|b6o${4U&8g6pywjfWbUzzL}E`jI8#=5Jo<{8koBJ1j|rV3UDzx=U6#Ex%(Yya|E zChl3br4#;2^j7Qj7B+`-^5NBP*dDQhKAXMug-ElOVeJ*Ng{)XnW@>JNfX*hZ6XC+k_4oJvkRF+}5wTU=1{@O4C5S4^Ta%X$yEOIE0nHEiMXb&+)u zU!9gZ66NM=a}BJf>YwsSEn>G-}2b!;LQn#LqGt| zy};X?7$0`RQ%S+$^ZefR7* z0h?+rQ}1k0k>0c6zO}i_emO1$F6~|oqUS!{=o!S}H;S!$*!nR!5n$}IvUSg^D$}Tk zvuLI8Ol|ei^6Qsm(T0q7K1Ewfu=)etGosFPyI9;0(!*;B&sgO+X_9+_aqioPsn&Ln zQ?0>X{W`HDMd=-cn!~?kT^bM0_9b*~I_)CnT#|);a0)w*tk6gpnNhazjy!ogtv0-0 z|Iji*b4?90@2edXGGHE`ik^!ggwA>s zsnOnoX^K`(AJCMF!P*CiDmiK84N#fb&5sKxqp&k43wZl(E&%g2H1IOetsHC)Z_zV4 zd*>m`Ne^NRZPEvR^7XT9k&SJGeA$I>VBXljYMp|4kBQ?Z@C}oX<2~GA%T(+ncLu<# z$=3%gh;GJBa1q(^fTqtQ1V?~?u<;kWo~B!@Q|TI;cx-qh-YEJTO>U*}RA66|n3~#- z28-9J_m(v>lTbB3{9u_bR8&|npIu8DIE5ZVr}3Xjz_r)JtsZ#3)*H}ZvQq(`%V<1( zvh#ul6c?PM=Yb>bacWj_s~elclH#sSpjo8&oON;~x7nn^c(st5faGw2$1Q%K{}W&-7oh^@4K(_C^6X!ay66S`l{>2OTFQ zD+W%J@p|Bwu@QuBekH7l-GWwc4PmwZ5{MqVR~V<&TiR5VSi{v$(ZQfl}~k2+dU z5Axisr-anEd)6We{1@9`u7K2aRP2KpiY-d6uR#Fr-cJ)8fln)7y$nyqX!H;QRPfSa z3-tnI2T>$7o>>it>}4RTac7&z?+A{Er0H{=ge``Tpf9hidM_$Y%c1*%OENq8{YR%X zxnf>~%(;~3N4sdvUgDmPql7-RU#a&K@v`7#)DiI@C5Q{2d1SzBqlSArBi9A7{PMAdWj6s$#7qP&JwHUV$+-du>v~!U;oGIOM!tWXH zHe8YP&NB;OZ3-KGI&PHLg3+fHVtnPClMO+|g4eR6tI|P4r7X zE%!a=;Dx{3Xcn5hr_M=w_8n7{x=Ek04a5?z6T!Dq8l_=wh@HE{iLDpI zjhzmmlmi)84a{ENR5bTBtUh>H?=3f~bJ~~(?lk`)u$$DVw=u3mAx|Ktwt@=-3SjlU zsUmZ^xviWTFeWkZz`038t&qc*+Qk3mD8UJRgFI@DkgK?%q+h$7VBJUOYor&G;6*Hw3;XXP%YwkMv#)iz zt?*=I33yr^nxrzD0m}r-4J)Gb^)l?`h}^f`*+pzowgnQ>wLvdf+MJ0Ov0WRL+dzg? zT=W(mFgp$nwM>-~u~TVeGTJF*#YvQ@UHA|!D22!)^U}Nhs$Iyj8x8^PWv9RXSqlApRXTCXS_Bvvs;ljON8YcC}(>UkD zBBA}FV>Gvvx#wCQaa^K0-MK|<(g{TRw__M{kG9#H@Kn$d$Eeuz%z~;ZP9+$&X@=G~ z1>W^v^*WaaK2bpaFt@N?iR74)4*pY1qV`BLYvHRxU+uZ-E$;Wv_W z@Qxslv{%g-vxjyXn4WV2YttB*vGNz@dcQ);;0`Cu;}GLQ$3-d~Ty7KiV!uAFcTLZ^ zy6?9VjHUTG@3#hkZ%QJh{@YvZu3%N9c(24kY;4hcDL{-dGMlRISJW_<$h$Ua5sl4uIWkGheb;#FcbA?G=X5`3 zpef|j24wD|RhJFxb!9p4-zWsn_P_ia*i}32*b7jlC_O1wbA7gC&{=TuhYP)12qQUW zxPT^mw5I!(f_wJvV?-aG)+Xd3d$z0mUhr8~?LJv{EImc^ytEofPBH4#iDfg%uq617 z(LJ(McPb5ReQ`XSUp7_U8$Y37rwE)fTK#@TMnmaLa(9cB|LD;(K3reZmVcsU%4Cb|Sk>$OgJeZ08RWILmHmHt!%?F86NiptjYyvV3C>af2} zywSK}$AdIoJ8DNWypA!s4dFprN$87)3?p%3mt2$+Qv-XW{4nu7Wf7E&WR4T*(bA)j^d~nZp1U$WNIHxNqb_kmWgr}x6THh3zH`2F0A{(uW%|Z zFWwgf zzlMI=?jOWBzzo^9)BGdF0FVxq0SZHC^X|O?!P|cwxSdLY>nPKYoqy123_1+Lu68wT zkGm=kSyfdzTO0rL&XF^IzL|8we$lkCb7N<@zg9XhGcNo#Dt6NDI&tD(lTQEe0U^XN zAehiY7cB<{u28epE`b#kjo0A@kUev_Ijo2O2qTcoK`uJQ0u_;WObkSFtrH@}^td=D zf>e!-p=5(yivQ3goZ|GmLi485D;a*bXN#y}fP* z^zsv7c$5*u_5Z|^i4ho5jX}Sng9?vAL}(|D>ZGVnN5hL0Dkn&vKeTjgF1?@N94ag^ zj8+bMqa2SSccGwP#)h3gn<_Pyv+xgQJvf&PrEc|X{Uj$%C#|RVu!4;sWbY>_Ko=T> z@pQO+Lvfty*vM${-N6;Xa6Jvz>zJxOPGpe>%EP{eiUS9qsl!J?`9q5NA2s*s7%)>7 zoWUs_va8TZ(A)mkfFE082yNKPoDSvxjKWm*Nm--n!HDQ9{Y2v6tbK;N{%zX0(tfkW zxJUeeREu8KbUck`WH@^SYZX!%h>cPhGuf0#>=2G@$zgrOOyx(0RWxiv}e;vKY zPq!>XJ|a54?!OW5BBb7aTBYS6B=9BP6;XWlSiQn0A9Z*;^75xWW{d4JhyJK5KE0kQ zr6?OTB+>}AOsr=O8D#{0L1?3HNw08dBr=_yiBfLTo31Je3*c839>oQvmYR${EepCv z?co=Sf{AIGR{pO@X#ObJ!x=V$YVKlX7DcD)EZ@qF_dTN5TB&dmjSGC}aMO@=e%3u= z{YP0RTU>54)|I@lytezJ2kclCU%V3K7mTva9Q2k5`rW{Dp&j^Ae)P>D( z6#9PBtNTOv6qTLwv*fzG@t@3gMfIn_V}A%gUcx*$I&jEmRV7|kv*fR^;C;iw3~OdE z8vW!U!!|SQO#_j|FwXqnBQOY@AbH0QmeEBIn2do0l92~O3b6F@D7Sb zMp7X!1VvF{0(Bav--){Re_&D94l3}4pjWr#)E}kSTv6(EzzXi*6VAgA3~OoFG=}|Q z7&V5Wa(I6j-V}#Jhv9f>I7p;o>EXzDIDZ&Unuaq)Dmfa?r-xr6{OQdJ$tRZoK<$&z zlo~{JV2tA!GpJWO02lv;>tq+St#=$H%qY_l)Dbx9gvTGpJ!U}TAX5kcFmOyWnyM?P zYD(3Qg*p~@zW(dSE5?5z#!q3vwpzfe8F@5&qt~dY1Ezo5b9}|+q@MGe_S_KeiS=oD zkZ;}-%WCP=jXAXRJI)jT{btEAw_3o&Tpkt`Rx%R5S%tG^e#^{F}0!@xA@ul_1IgS3rVb|n?_>o`=>{vBBF UoOs=6@h%0vEot(c1jDqy1Eecdl>h($ literal 0 HcmV?d00001 From 974c08596b50664b419791e589c363abac7c80eb Mon Sep 17 00:00:00 2001 From: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com> Date: Wed, 18 Sep 2024 13:43:30 +1200 Subject: [PATCH 098/138] Fix AudioSystem nullability checks for engine PR (#32233) --- Content.Client/Audio/AmbientSoundSystem.cs | 3 +++ Content.Client/Audio/ClientGlobalSoundSystem.cs | 4 ++-- Content.Client/Audio/ContentAudioSystem.AmbientMusic.cs | 4 ++-- Content.Client/Audio/ContentAudioSystem.LobbyMusic.cs | 2 +- Content.Client/Traits/ParacusiaSystem.cs | 2 +- Content.Client/Weather/WeatherSystem.cs | 9 +++++---- Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs | 2 +- .../Kitchen/EntitySystems/ReagentGrinderSystem.cs | 2 +- .../Mech/Equipment/EntitySystems/MechGrabberSystem.cs | 2 +- Content.Server/Salvage/SalvageSystem.Runner.cs | 4 ++-- .../Shuttles/Systems/ShuttleSystem.FasterThanLight.cs | 3 ++- 11 files changed, 21 insertions(+), 16 deletions(-) diff --git a/Content.Client/Audio/AmbientSoundSystem.cs b/Content.Client/Audio/AmbientSoundSystem.cs index ca6336b91b8..b525747aa9c 100644 --- a/Content.Client/Audio/AmbientSoundSystem.cs +++ b/Content.Client/Audio/AmbientSoundSystem.cs @@ -306,6 +306,9 @@ private void ProcessNearbyAmbience(TransformComponent playerXform) .WithMaxDistance(comp.Range); var stream = _audio.PlayEntity(comp.Sound, Filter.Local(), uid, false, audioParams); + if (stream == null) + continue; + _playingSounds[sourceEntity] = (stream.Value.Entity, comp.Sound, key); playingCount++; diff --git a/Content.Client/Audio/ClientGlobalSoundSystem.cs b/Content.Client/Audio/ClientGlobalSoundSystem.cs index 7c77865f741..50c3971d95a 100644 --- a/Content.Client/Audio/ClientGlobalSoundSystem.cs +++ b/Content.Client/Audio/ClientGlobalSoundSystem.cs @@ -67,7 +67,7 @@ private void PlayAdminSound(AdminSoundEvent soundEvent) if(!_adminAudioEnabled) return; var stream = _audio.PlayGlobal(soundEvent.Filename, Filter.Local(), false, soundEvent.AudioParams); - _adminAudio.Add(stream.Value.Entity); + _adminAudio.Add(stream?.Entity); } private void PlayStationEventMusic(StationEventMusicEvent soundEvent) @@ -76,7 +76,7 @@ private void PlayStationEventMusic(StationEventMusicEvent soundEvent) if(!_eventAudioEnabled || _eventAudio.ContainsKey(soundEvent.Type)) return; var stream = _audio.PlayGlobal(soundEvent.Filename, Filter.Local(), false, soundEvent.AudioParams); - _eventAudio.Add(soundEvent.Type, stream.Value.Entity); + _eventAudio.Add(soundEvent.Type, stream?.Entity); } private void PlayGameSound(GameGlobalSoundEvent soundEvent) diff --git a/Content.Client/Audio/ContentAudioSystem.AmbientMusic.cs b/Content.Client/Audio/ContentAudioSystem.AmbientMusic.cs index d60c978ccf5..bf7ab26cba2 100644 --- a/Content.Client/Audio/ContentAudioSystem.AmbientMusic.cs +++ b/Content.Client/Audio/ContentAudioSystem.AmbientMusic.cs @@ -213,9 +213,9 @@ private void UpdateAmbientMusic() false, AudioParams.Default.WithVolume(_musicProto.Sound.Params.Volume + _volumeSlider)); - _ambientMusicStream = strim.Value.Entity; + _ambientMusicStream = strim?.Entity; - if (_musicProto.FadeIn) + if (_musicProto.FadeIn && strim != null) { FadeIn(_ambientMusicStream, strim.Value.Component, AmbientMusicFadeTime); } diff --git a/Content.Client/Audio/ContentAudioSystem.LobbyMusic.cs b/Content.Client/Audio/ContentAudioSystem.LobbyMusic.cs index 92c5b7a4191..9864dbcb2a9 100644 --- a/Content.Client/Audio/ContentAudioSystem.LobbyMusic.cs +++ b/Content.Client/Audio/ContentAudioSystem.LobbyMusic.cs @@ -185,7 +185,7 @@ private void PlaySoundtrack(string soundtrackFilename) false, _lobbySoundtrackParams.WithVolume(_lobbySoundtrackParams.Volume + SharedAudioSystem.GainToVolume(_configManager.GetCVar(CCVars.LobbyMusicVolume))) ); - if (playResult.Value.Entity == default) + if (playResult == null) { _sawmill.Warning( $"Tried to play lobby soundtrack '{{Filename}}' using {nameof(SharedAudioSystem)}.{nameof(SharedAudioSystem.PlayGlobal)} but it returned default value of EntityUid!", diff --git a/Content.Client/Traits/ParacusiaSystem.cs b/Content.Client/Traits/ParacusiaSystem.cs index 3789f24cb0d..af4d8ef278f 100644 --- a/Content.Client/Traits/ParacusiaSystem.cs +++ b/Content.Client/Traits/ParacusiaSystem.cs @@ -69,7 +69,7 @@ private void PlayParacusiaSounds(EntityUid uid) var newCoords = Transform(uid).Coordinates.Offset(randomOffset); // Play the sound - paracusia.Stream = _audio.PlayStatic(paracusia.Sounds, uid, newCoords).Value.Entity; + paracusia.Stream = _audio.PlayStatic(paracusia.Sounds, uid, newCoords)?.Entity; } } diff --git a/Content.Client/Weather/WeatherSystem.cs b/Content.Client/Weather/WeatherSystem.cs index a0e8a44f40b..975831392cb 100644 --- a/Content.Client/Weather/WeatherSystem.cs +++ b/Content.Client/Weather/WeatherSystem.cs @@ -47,10 +47,11 @@ protected override void Run(EntityUid uid, WeatherData weather, WeatherPrototype if (!Timing.IsFirstTimePredicted || weatherProto.Sound == null) return; - weather.Stream ??= _audio.PlayGlobal(weatherProto.Sound, Filter.Local(), true).Value.Entity; + weather.Stream ??= _audio.PlayGlobal(weatherProto.Sound, Filter.Local(), true)?.Entity; + + if (!TryComp(weather.Stream, out AudioComponent? comp)) + return; - var stream = weather.Stream.Value; - var comp = Comp(stream); var occlusion = 0f; // Work out tiles nearby to determine volume. @@ -115,7 +116,7 @@ protected override void Run(EntityUid uid, WeatherData weather, WeatherPrototype var alpha = GetPercent(weather, uid); alpha *= SharedAudioSystem.VolumeToGain(weatherProto.Sound.Params.Volume); - _audio.SetGain(stream, alpha, comp); + _audio.SetGain(weather.Stream, alpha, comp); comp.Occlusion = occlusion; } diff --git a/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs b/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs index 9f43f760185..1ac02ac8825 100644 --- a/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs +++ b/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs @@ -112,7 +112,7 @@ private void OnCookStart(Entity ent, ref ComponentStar SetAppearance(ent.Owner, MicrowaveVisualState.Cooking, microwaveComponent); microwaveComponent.PlayingStream = - _audio.PlayPvs(microwaveComponent.LoopingSound, ent, AudioParams.Default.WithLoop(true).WithMaxDistance(5)).Value.Entity; + _audio.PlayPvs(microwaveComponent.LoopingSound, ent, AudioParams.Default.WithLoop(true).WithMaxDistance(5))?.Entity; } private void OnCookStop(Entity ent, ref ComponentShutdown args) diff --git a/Content.Server/Kitchen/EntitySystems/ReagentGrinderSystem.cs b/Content.Server/Kitchen/EntitySystems/ReagentGrinderSystem.cs index 71536ddf8eb..12c5a30a4b2 100644 --- a/Content.Server/Kitchen/EntitySystems/ReagentGrinderSystem.cs +++ b/Content.Server/Kitchen/EntitySystems/ReagentGrinderSystem.cs @@ -305,7 +305,7 @@ private void DoWork(EntityUid uid, ReagentGrinderComponent reagentGrinder, Grind active.Program = program; reagentGrinder.AudioStream = _audioSystem.PlayPvs(sound, uid, - AudioParams.Default.WithPitchScale(1 / reagentGrinder.WorkTimeMultiplier)).Value.Entity; //slightly higher pitched + AudioParams.Default.WithPitchScale(1 / reagentGrinder.WorkTimeMultiplier))?.Entity; //slightly higher pitched _userInterfaceSystem.ServerSendUiMessage(uid, ReagentGrinderUiKey.Key, new ReagentGrinderWorkStartedMessage(program)); } diff --git a/Content.Server/Mech/Equipment/EntitySystems/MechGrabberSystem.cs b/Content.Server/Mech/Equipment/EntitySystems/MechGrabberSystem.cs index aa28a8063c0..08120f5c296 100644 --- a/Content.Server/Mech/Equipment/EntitySystems/MechGrabberSystem.cs +++ b/Content.Server/Mech/Equipment/EntitySystems/MechGrabberSystem.cs @@ -155,7 +155,7 @@ private void OnInteract(EntityUid uid, MechGrabberComponent component, UserActiv return; args.Handled = true; - component.AudioStream = _audio.PlayPvs(component.GrabSound, uid).Value.Entity; + component.AudioStream = _audio.PlayPvs(component.GrabSound, uid)?.Entity; var doAfterArgs = new DoAfterArgs(EntityManager, args.User, component.GrabDelay, new GrabberDoAfterEvent(), uid, target: target, used: uid) { BreakOnMove = true diff --git a/Content.Server/Salvage/SalvageSystem.Runner.cs b/Content.Server/Salvage/SalvageSystem.Runner.cs index 23a575413ed..921d9667094 100644 --- a/Content.Server/Salvage/SalvageSystem.Runner.cs +++ b/Content.Server/Salvage/SalvageSystem.Runner.cs @@ -154,8 +154,8 @@ private void UpdateRunner() } else if (comp.Stream == null && remaining < audioLength) { - var audio = _audio.PlayPvs(comp.Sound, uid).Value; - comp.Stream = audio.Entity; + var audio = _audio.PlayPvs(comp.Sound, uid); + comp.Stream = audio?.Entity; _audio.SetMapAudio(audio); comp.Stage = ExpeditionStage.MusicCountdown; Dirty(uid, comp); diff --git a/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs b/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs index e544c1538d1..ce6a914847f 100644 --- a/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs +++ b/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs @@ -397,7 +397,8 @@ private void UpdateFTLStarting(Entity entity) new EntityCoordinates(fromMapUid.Value, _mapSystem.GetGridPosition(entity.Owner)), true, startupAudio.Params); _audio.SetPlaybackPosition(clippedAudio, entity.Comp1.StartupTime); - clippedAudio.Value.Component.Flags |= AudioFlags.NoOcclusion; + if (clippedAudio != null) + clippedAudio.Value.Component.Flags |= AudioFlags.NoOcclusion; } // Offset the start by buffer range just to avoid overlap. From 2bceaad7854a423836e81c7b78985de1b98e9b8f Mon Sep 17 00:00:00 2001 From: Winkarst <74284083+Winkarst-cpu@users.noreply.github.com> Date: Wed, 18 Sep 2024 04:49:37 +0300 Subject: [PATCH 099/138] Use TurfSystem.IsTileBlocked instead of TurfHelpers (#32174) * Use TurfSystem.IsTileBlocked instead of TurfHelpers * ! --- .../Engineering/EntitySystems/SpawnAfterInteractSystem.cs | 4 +++- Content.Server/Respawn/SpecialRespawnSystem.cs | 7 +++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Content.Server/Engineering/EntitySystems/SpawnAfterInteractSystem.cs b/Content.Server/Engineering/EntitySystems/SpawnAfterInteractSystem.cs index 8391e8faada..407f877515a 100644 --- a/Content.Server/Engineering/EntitySystems/SpawnAfterInteractSystem.cs +++ b/Content.Server/Engineering/EntitySystems/SpawnAfterInteractSystem.cs @@ -4,6 +4,7 @@ using Content.Shared.DoAfter; using Content.Shared.Interaction; using Content.Shared.Maps; +using Content.Shared.Physics; using Content.Shared.Stacks; using JetBrains.Annotations; using Robust.Shared.Map.Components; @@ -15,6 +16,7 @@ public sealed class SpawnAfterInteractSystem : EntitySystem { [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; [Dependency] private readonly StackSystem _stackSystem = default!; + [Dependency] private readonly TurfSystem _turfSystem = default!; public override void Initialize() { @@ -36,7 +38,7 @@ private async void HandleAfterInteract(EntityUid uid, SpawnAfterInteractComponen bool IsTileClear() { - return tileRef.Tile.IsEmpty == false && !tileRef.IsBlockedTurf(true); + return tileRef.Tile.IsEmpty == false && !_turfSystem.IsTileBlocked(tileRef, CollisionGroup.MobMask); } if (!IsTileClear()) diff --git a/Content.Server/Respawn/SpecialRespawnSystem.cs b/Content.Server/Respawn/SpecialRespawnSystem.cs index 8c86449008a..6d398db259d 100644 --- a/Content.Server/Respawn/SpecialRespawnSystem.cs +++ b/Content.Server/Respawn/SpecialRespawnSystem.cs @@ -2,16 +2,15 @@ using Content.Server.Atmos.EntitySystems; using Content.Server.Chat.Managers; using Content.Server.GameTicking; -using Content.Shared.Station.Components; -using Content.Server.Station.Systems; using Content.Shared.Database; using Content.Shared.Maps; using Content.Shared.Physics; using Content.Shared.Respawn; +using Content.Shared.Station.Components; using Robust.Shared.Map; using Robust.Shared.Map.Components; -using Robust.Shared.Random; using Robust.Shared.Prototypes; +using Robust.Shared.Random; namespace Content.Server.Respawn; @@ -179,7 +178,7 @@ public bool TryFindRandomTile(EntityUid targetGrid, EntityUid targetMap, int max foreach (var newTileRef in grid.GetTilesIntersecting(circle)) { - if (newTileRef.IsSpace(_tileDefinitionManager) || newTileRef.IsBlockedTurf(true) || !_atmosphere.IsTileMixtureProbablySafe(targetGrid, targetMap, mapTarget)) + if (newTileRef.IsSpace(_tileDefinitionManager) || _turf.IsTileBlocked(newTileRef, CollisionGroup.MobMask) || !_atmosphere.IsTileMixtureProbablySafe(targetGrid, targetMap, mapTarget)) continue; found = true; From 54e4cfecfe44109b0c5333d3044ded6199105459 Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Wed, 18 Sep 2024 12:32:16 +1000 Subject: [PATCH 100/138] Update submodule to 235.0.0 (#32265) --- Resources/Prototypes/Entities/Mobs/Player/silicon.yml | 6 +++--- RobustToolbox | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml index 62dbf3ee106..493cfdf6cb6 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml @@ -2,7 +2,7 @@ - type: entity id: AiHeld description: Components added / removed from an entity that gets inserted into an AI core. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: IntrinsicRadioReceiver - type: IntrinsicRadioTransmitter @@ -341,7 +341,7 @@ - type: entity id: StationAiBrain parent: PositronicBrain - noSpawn: true + categories: [ HideSpawnMenu ] suffix: DO NOT MAP components: - type: Sprite @@ -382,7 +382,7 @@ id: StationAiHolo name: AI eye description: The AI's viewer. - noSpawn: true + categories: [ HideSpawnMenu ] suffix: DO NOT MAP components: - type: NoFTL diff --git a/RobustToolbox b/RobustToolbox index 0f60ad9018f..c86cb0b7951 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit 0f60ad9018f54f9b49da1810bbffa01e2c5975f7 +Subproject commit c86cb0b7951cc4a662c7292138c5f45d868c5f58 From a1237910c5e5919b2a3742b6628ff45d3a9982a0 Mon Sep 17 00:00:00 2001 From: lzk <124214523+lzk228@users.noreply.github.com> Date: Wed, 18 Sep 2024 09:37:35 +0200 Subject: [PATCH 101/138] Fix bagel vox box (#32208) Fix vox box on bagel --- Resources/Maps/bagel.yml | 48 ++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/Resources/Maps/bagel.yml b/Resources/Maps/bagel.yml index 7505068a50a..d661e097c36 100644 --- a/Resources/Maps/bagel.yml +++ b/Resources/Maps/bagel.yml @@ -154188,12 +154188,36 @@ entities: parent: 60 - proto: WindoorSecure entities: + - uid: 2538 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 13.5,-11.5 + parent: 60 + - type: DeviceLinkSink + invokeCounter: 1 + - type: DeviceLinkSource + linkedPorts: + 3481: + - DoorStatus: DoorBolt - uid: 3269 components: - type: Transform rot: -1.5707963267948966 rad pos: 23.5,-46.5 parent: 60 + - uid: 3481 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 14.5,-13.5 + parent: 60 + - type: DeviceLinkSink + invokeCounter: 1 + - type: DeviceLinkSource + linkedPorts: + 2538: + - DoorStatus: DoorBolt - uid: 3911 components: - type: Transform @@ -154249,30 +154273,6 @@ entities: rot: -1.5707963267948966 rad pos: -23.5,-9.5 parent: 60 - - uid: 2538 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 14.5,-13.5 - parent: 60 - - type: DeviceLinkSink - invokeCounter: 1 - - type: DeviceLinkSource - linkedPorts: - 3481: - - DoorStatus: DoorBolt - - uid: 3481 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 13.5,-11.5 - parent: 60 - - type: DeviceLinkSink - invokeCounter: 1 - - type: DeviceLinkSource - linkedPorts: - 2538: - - DoorStatus: DoorBolt - uid: 12188 components: - type: Transform From 8322b1c2d15640a2c81c4746200e857c056005d3 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Wed, 18 Sep 2024 15:28:09 +0200 Subject: [PATCH 102/138] New publish workflow for Robust.Cdn (#32222) This uses multiple API requests to directly send the publish to the CDN server, no more GitHub artifacts. Faster, less moving parts. Needs Robust.Cdn 2.2.0 --- .github/workflows/publish.yml | 18 +------- Tools/publish_multi_request.py | 78 ++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 17 deletions(-) create mode 100644 Tools/publish_multi_request.py diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 16cb5017d6a..d08ae135020 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -41,21 +41,10 @@ jobs: - name: Package client run: dotnet run --project Content.Packaging client --no-wipe-release - - name: Upload build artifact - id: artifact-upload-step - uses: actions/upload-artifact@v4 - with: - name: build - path: release/*.zip - compression-level: 0 - retention-days: 0 - - name: Publish version - run: Tools/publish_github_artifact.py + run: Tools/publish_multi_request.py env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }} - ARTIFACT_ID: ${{ steps.artifact-upload-step.outputs.artifact-id }} GITHUB_REPOSITORY: ${{ vars.GITHUB_REPOSITORY }} - name: Publish changelog (Discord) @@ -68,8 +57,3 @@ jobs: run: Tools/actions_changelog_rss.py env: CHANGELOG_RSS_KEY: ${{ secrets.CHANGELOG_RSS_KEY }} - - - uses: geekyeggo/delete-artifact@v5 - if: always() - with: - name: build diff --git a/Tools/publish_multi_request.py b/Tools/publish_multi_request.py new file mode 100644 index 00000000000..a63359afd6c --- /dev/null +++ b/Tools/publish_multi_request.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python3 + +import requests +import os +import subprocess +from typing import Iterable + +PUBLISH_TOKEN = os.environ["PUBLISH_TOKEN"] +VERSION = os.environ["GITHUB_SHA"] + +RELEASE_DIR = "release" + +# +# CONFIGURATION PARAMETERS +# Forks should change these to publish to their own infrastructure. +# +ROBUST_CDN_URL = "https://wizards.cdn.spacestation14.com/" +FORK_ID = "wizards" + +def main(): + session = requests.Session() + session.headers = { + "Authorization": f"Bearer {PUBLISH_TOKEN}", + } + + print(f"Starting publish on Robust.Cdn for version {VERSION}") + + data = { + "version": VERSION, + "engineVersion": get_engine_version(), + } + headers = { + "Content-Type": "application/json" + } + resp = session.post(f"{ROBUST_CDN_URL}fork/{FORK_ID}/publish/start", json=data, headers=headers) + resp.raise_for_status() + print("Publish successfully started, adding files...") + + for file in get_files_to_publish(): + print(f"Publishing {file}") + with open(file, "rb") as f: + headers = { + "Content-Type": "application/octet-stream", + "Robust-Cdn-Publish-File": os.path.basename(file), + "Robust-Cdn-Publish-Version": VERSION + } + resp = session.post(f"{ROBUST_CDN_URL}fork/{FORK_ID}/publish/file", data=f, headers=headers) + + resp.raise_for_status() + + print("Successfully pushed files, finishing publish...") + + data = { + "version": VERSION + } + headers = { + "Content-Type": "application/json" + } + resp = session.post(f"{ROBUST_CDN_URL}fork/{FORK_ID}/publish/finish", json=data, headers=headers) + resp.raise_for_status() + + print("SUCCESS!") + + +def get_files_to_publish() -> Iterable[str]: + for file in os.listdir(RELEASE_DIR): + yield os.path.join(RELEASE_DIR, file) + + +def get_engine_version() -> str: + proc = subprocess.run(["git", "describe","--tags", "--abbrev=0"], stdout=subprocess.PIPE, cwd="RobustToolbox", check=True, encoding="UTF-8") + tag = proc.stdout.strip() + assert tag.startswith("v") + return tag[1:] # Cut off v prefix. + + +if __name__ == '__main__': + main() From b55366cf9be9f23ec8d8f17c590cb62c57f92d54 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Wed, 18 Sep 2024 16:09:25 +0200 Subject: [PATCH 103/138] chmod +x publish_multi_request.py (#32274) Fuck. --- Tools/publish_multi_request.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 Tools/publish_multi_request.py diff --git a/Tools/publish_multi_request.py b/Tools/publish_multi_request.py old mode 100644 new mode 100755 From 489938cdb14755b93181aa0de8899363e075c5d3 Mon Sep 17 00:00:00 2001 From: AsnDen <75905158+AsnDen@users.noreply.github.com> Date: Wed, 18 Sep 2024 17:54:00 +0300 Subject: [PATCH 104/138] ghost-role-information-silicon-rules (#32275) changes missing ghost-role-information-rules-default-silicon to ghost-role-information-silicon-rules --- Resources/Prototypes/Entities/Mobs/Player/silicon.yml | 4 ++-- .../Devices/Syndicate_Gadgets/reinforcement_teleporter.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml index 493cfdf6cb6..15878a4017d 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml @@ -462,7 +462,7 @@ - type: GhostRole name: ghost-role-information-syndicate-cyborg-assault-name description: ghost-role-information-syndicate-cyborg-description - rules: ghost-role-information-rules-default-silicon + rules: ghost-role-information-silicon-rules raffle: settings: default - type: GhostTakeoverAvailable @@ -495,7 +495,7 @@ - type: GhostRole name: ghost-role-information-syndicate-cyborg-saboteur-name description: ghost-role-information-syndicate-cyborg-description - rules: ghost-role-information-rules-default-silicon + rules: ghost-role-information-silicon-rules raffle: settings: default - type: GhostTakeoverAvailable diff --git a/Resources/Prototypes/Entities/Objects/Devices/Syndicate_Gadgets/reinforcement_teleporter.yml b/Resources/Prototypes/Entities/Objects/Devices/Syndicate_Gadgets/reinforcement_teleporter.yml index 1a7a02e7337..71f98d81c96 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/Syndicate_Gadgets/reinforcement_teleporter.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/Syndicate_Gadgets/reinforcement_teleporter.yml @@ -100,7 +100,7 @@ - type: GhostRole name: ghost-role-information-syndicate-cyborg-assault-name description: ghost-role-information-syndicate-cyborg-description - rules: ghost-role-information-rules-default-silicon + rules: ghost-role-information-silicon-rules raffle: settings: default - type: GhostRoleMobSpawner From ed83593948ef9863e0be8c5b900d1a116c4854ab Mon Sep 17 00:00:00 2001 From: Calecute <34964590+Calecute@users.noreply.github.com> Date: Wed, 18 Sep 2024 12:15:34 -0300 Subject: [PATCH 105/138] Fix guidebook cakebatter recipe (#32276) Bugfix: Add 5 milk to cake batter recipe in the guidebook to correctly reflect new recipe --- Resources/ServerInfo/Guidebook/Service/FoodRecipes.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/ServerInfo/Guidebook/Service/FoodRecipes.xml b/Resources/ServerInfo/Guidebook/Service/FoodRecipes.xml index 3eb9c2ca2f2..7e5e20139b0 100644 --- a/Resources/ServerInfo/Guidebook/Service/FoodRecipes.xml +++ b/Resources/ServerInfo/Guidebook/Service/FoodRecipes.xml @@ -13,7 +13,7 @@ WARNING: This is not an automatically generated list, things here may become out - Tortila Dough = 15 Cornmeal, 10 Water - Tofu = 5 Enzyme (Catalyst), 30 Soy Milk - Pie Dough = 2 Eggs (12u), 15 Flour, 5 Table Salt -- Cake Batter = 2 Eggs(12u), 15 flour, 5 Sugar +- Cake Batter = 2 Eggs(12u), 15 flour, 5 Sugar, 5 Milk - Vegan Cake Batter = 15 Soy Milk, 15 Flour, 5 Sugar - Butter = 30 Milk, 5 Table Salt (Catalyst) - Cheese Wheel = 5 Enzyme (Catalyst), 40 Milk From 697f4f5ef94696f54a527103a8ee001d73161afc Mon Sep 17 00:00:00 2001 From: PJBot Date: Wed, 18 Sep 2024 15:16:42 +0000 Subject: [PATCH 106/138] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 11609a0efc9..ed88f5c696d 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Plykiya - changes: - - message: You can now drop food and drinks to stop consuming it. - type: Fix - id: 6891 - time: '2024-07-09T23:12:40.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29854 - author: Boaz1111 changes: - message: Guitars can now be worn in the suit storage slot @@ -3917,3 +3910,10 @@ id: 7390 time: '2024-09-17T22:09:55.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/31951 +- author: Calecute + changes: + - message: Corrected cake batter recipe in guidebook + type: Fix + id: 7391 + time: '2024-09-18T15:15:34.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/32276 From 9fad1ab14ece4ea2139dedb9a185532b8ed520e1 Mon Sep 17 00:00:00 2001 From: chavonadelal <156101927+chavonadelal@users.noreply.github.com> Date: Wed, 18 Sep 2024 22:10:53 +0300 Subject: [PATCH 107/138] Wires ui tooltip localization (#32284) * Wires ui tooltip localization * Corrections after review --- Content.Client/Wires/UI/WiresMenu.cs | 9 +-------- .../Locale/en-US/wires/components/wires-component.ftl | 6 ++++++ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/Content.Client/Wires/UI/WiresMenu.cs b/Content.Client/Wires/UI/WiresMenu.cs index eccc548297c..77fc3accceb 100644 --- a/Content.Client/Wires/UI/WiresMenu.cs +++ b/Content.Client/Wires/UI/WiresMenu.cs @@ -584,17 +584,10 @@ public StatusLight(StatusLightData data, IResourceCache resourceCache) private sealed class HelpPopup : Popup { - private const string Text = "Click on the gold contacts with a multitool in hand to pulse their wire.\n" + - "Click on the wires with a pair of wirecutters in hand to cut/mend them.\n\n" + - "The lights at the top show the state of the machine, " + - "messing with wires will probably do stuff to them.\n" + - "Wire layouts are different each round, " + - "but consistent between machines of the same type."; - public HelpPopup() { var label = new RichTextLabel(); - label.SetMessage(Text); + label.SetMessage(Loc.GetString("wires-menu-help-popup")); AddChild(new PanelContainer { StyleClasses = {ExamineSystem.StyleClassEntityTooltip}, diff --git a/Resources/Locale/en-US/wires/components/wires-component.ftl b/Resources/Locale/en-US/wires/components/wires-component.ftl index be27c270bb4..e98e5c21cab 100644 --- a/Resources/Locale/en-US/wires/components/wires-component.ftl +++ b/Resources/Locale/en-US/wires/components/wires-component.ftl @@ -10,3 +10,9 @@ wires-component-ui-on-receive-message-cannot-mend-uncut-wire = You can't mend a wires-menu-name-label = Wires wires-menu-dead-beef-text = DEAD-BEEF +wires-menu-help-popup = + Click on the gold contacts with a multitool in hand to pulse their wire. + Click on the wires with a pair of wirecutters in hand to cut/mend them. + + The lights at the top show the state of the machine, messing with wires will probably do stuff to them. + Wire layouts are different each round, but consistent between machines of the same type. From 6d4177567eb921f30ffad8588a77068dc0bb96ca Mon Sep 17 00:00:00 2001 From: chavonadelal <156101927+chavonadelal@users.noreply.github.com> Date: Wed, 18 Sep 2024 22:16:47 +0300 Subject: [PATCH 108/138] Localization of the shuttle call sender (#32286) --- Content.Server/RoundEnd/RoundEndSystem.cs | 6 +++--- Resources/Locale/en-US/round-end/round-end-system.ftl | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Content.Server/RoundEnd/RoundEndSystem.cs b/Content.Server/RoundEnd/RoundEndSystem.cs index 82bdb78816f..bb5934f3f08 100644 --- a/Content.Server/RoundEnd/RoundEndSystem.cs +++ b/Content.Server/RoundEnd/RoundEndSystem.cs @@ -125,7 +125,7 @@ public bool IsRoundEndRequested() return _countdownTokenSource != null; } - public void RequestRoundEnd(EntityUid? requester = null, bool checkCooldown = true, string text = "round-end-system-shuttle-called-announcement", string name = "Station") + public void RequestRoundEnd(EntityUid? requester = null, bool checkCooldown = true, string text = "round-end-system-shuttle-called-announcement", string name = "round-end-system-shuttle-sender-announcement") { var duration = DefaultCountdownDuration; @@ -143,7 +143,7 @@ public void RequestRoundEnd(EntityUid? requester = null, bool checkCooldown = tr RequestRoundEnd(duration, requester, checkCooldown, text, name); } - public void RequestRoundEnd(TimeSpan countdownTime, EntityUid? requester = null, bool checkCooldown = true, string text = "round-end-system-shuttle-called-announcement", string name = "Station") + public void RequestRoundEnd(TimeSpan countdownTime, EntityUid? requester = null, bool checkCooldown = true, string text = "round-end-system-shuttle-called-announcement", string name = "round-end-system-shuttle-sender-announcement") { if (_gameTicker.RunLevel != GameRunLevel.InRound) return; @@ -183,7 +183,7 @@ public void RequestRoundEnd(TimeSpan countdownTime, EntityUid? requester = null, _chatSystem.DispatchGlobalAnnouncement(Loc.GetString(text, ("time", time), ("units", Loc.GetString(units))), - name, + Loc.GetString(name), false, null, Color.Gold); diff --git a/Resources/Locale/en-US/round-end/round-end-system.ftl b/Resources/Locale/en-US/round-end/round-end-system.ftl index f86851506bc..30069f71713 100644 --- a/Resources/Locale/en-US/round-end/round-end-system.ftl +++ b/Resources/Locale/en-US/round-end/round-end-system.ftl @@ -4,6 +4,7 @@ round-end-system-shuttle-called-announcement = An emergency shuttle has been sen round-end-system-shuttle-already-called-announcement = An emergency shuttle has already been sent. round-end-system-shuttle-auto-called-announcement = An automatic crew shift change shuttle has been sent. ETA: {$time} {$units}. Recall the shuttle to extend the shift. round-end-system-shuttle-recalled-announcement = The emergency shuttle has been recalled. +round-end-system-shuttle-sender-announcement = Station round-end-system-round-restart-eta-announcement = Restarting the round in {$time} {$units}... eta-units-minutes = minutes From 55b7e3ce0e5216e06db64f6d4c4408a20f48c8c3 Mon Sep 17 00:00:00 2001 From: Skarletto <122584947+Skarletto@users.noreply.github.com> Date: Wed, 18 Sep 2024 17:51:11 -0400 Subject: [PATCH 109/138] change jamjar glasses description (#32215) nerds only please --- Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml b/Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml index 368cefe9cb4..467bbf873f2 100644 --- a/Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml +++ b/Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml @@ -100,7 +100,7 @@ parent: ClothingEyesBase id: ClothingEyesGlassesJamjar name: jamjar glasses - description: Also known as Virginity Protectors. + description: These retro glasses remind you of a simpler time. components: - type: Sprite sprite: Clothing/Eyes/Glasses/jamjar.rsi From 58119bc3f769cad480b3daaf3dbc5335d8a9c1a9 Mon Sep 17 00:00:00 2001 From: beck-thompson <107373427+beck-thompson@users.noreply.github.com> Date: Wed, 18 Sep 2024 14:58:58 -0700 Subject: [PATCH 110/138] Fix recycler eating materials (Salvage mains rejoice) (#32144) first commit --- Resources/Prototypes/Entities/Structures/Machines/recycler.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/Resources/Prototypes/Entities/Structures/Machines/recycler.yml b/Resources/Prototypes/Entities/Structures/Machines/recycler.yml index 8bbbad6c0d1..f62923fe2af 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/recycler.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/recycler.yml @@ -85,6 +85,7 @@ volume: -3 cutOffSound: false - type: MaterialStorage + insertOnInteract: false - type: Conveyor - type: Rotatable - type: Repairable From 64aab9e41dbef39cd1100dc5eca02e6167fc6572 Mon Sep 17 00:00:00 2001 From: PJBot Date: Wed, 18 Sep 2024 22:00:05 +0000 Subject: [PATCH 111/138] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index ed88f5c696d..9879e7f9a32 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Boaz1111 - changes: - - message: Guitars can now be worn in the suit storage slot - type: Add - id: 6892 - time: '2024-07-09T23:28:10.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29048 - author: Winkarst-cpu changes: - message: Fixed popup spam when trying to open borg's UI while the borg is locked. @@ -3917,3 +3910,10 @@ id: 7391 time: '2024-09-18T15:15:34.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/32276 +- author: Beck Thompson + changes: + - message: Recycler no longer allows basic materials to be inserted into it. + type: Fix + id: 7392 + time: '2024-09-18T21:58:59.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/32144 From ba24ebfb4f9e887d08b885424241e3365ff43104 Mon Sep 17 00:00:00 2001 From: chavonadelal <156101927+chavonadelal@users.noreply.github.com> Date: Thu, 19 Sep 2024 01:21:53 +0300 Subject: [PATCH 112/138] Localization cooldown/remaining string in alerts (#32282) Cooldown localization --- Content.Client/Actions/UI/ActionAlertTooltip.cs | 2 +- Resources/Locale/en-US/actions/ui/actionslot.ftl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Content.Client/Actions/UI/ActionAlertTooltip.cs b/Content.Client/Actions/UI/ActionAlertTooltip.cs index f805f6643d2..2425cdefb91 100644 --- a/Content.Client/Actions/UI/ActionAlertTooltip.cs +++ b/Content.Client/Actions/UI/ActionAlertTooltip.cs @@ -101,7 +101,7 @@ protected override void FrameUpdate(FrameEventArgs args) { var duration = Cooldown.Value.End - Cooldown.Value.Start; - if (!FormattedMessage.TryFromMarkup($"[color=#a10505]{(int) duration.TotalSeconds} sec cooldown ({(int) timeLeft.TotalSeconds + 1} sec remaining)[/color]", out var markup)) + if (!FormattedMessage.TryFromMarkup(Loc.GetString("ui-actionslot-duration", ("duration", (int)duration.TotalSeconds), ("timeLeft", (int)timeLeft.TotalSeconds + 1)), out var markup)) return; _cooldownLabel.SetMessage(markup); diff --git a/Resources/Locale/en-US/actions/ui/actionslot.ftl b/Resources/Locale/en-US/actions/ui/actionslot.ftl index 332054f10e9..c0deaad248c 100644 --- a/Resources/Locale/en-US/actions/ui/actionslot.ftl +++ b/Resources/Locale/en-US/actions/ui/actionslot.ftl @@ -1,2 +1,2 @@ ui-actionslot-charges = Uses left: {$charges} - +ui-actionslot-duration = [color=#a10505] {$duration} sec cooldown ({$timeLeft} sec remaining)[/color] From 8a924c84ae57dfe18fe0c27f995b4ea16be6a527 Mon Sep 17 00:00:00 2001 From: deltanedas <39013340+deltanedas@users.noreply.github.com> Date: Wed, 18 Sep 2024 22:36:44 +0000 Subject: [PATCH 113/138] add interaction success/failure events (#32216) * add interaction success/failure events * pro --------- Co-authored-by: deltanedas <@deltanedas:kde.org> --- .../Interaction/Events/InteractionFailureEvent.cs | 7 +++++++ .../Interaction/Events/InteractionSuccessEvent.cs | 7 +++++++ Content.Shared/Interaction/InteractionPopupSystem.cs | 7 +++++++ 3 files changed, 21 insertions(+) create mode 100644 Content.Shared/Interaction/Events/InteractionFailureEvent.cs create mode 100644 Content.Shared/Interaction/Events/InteractionSuccessEvent.cs diff --git a/Content.Shared/Interaction/Events/InteractionFailureEvent.cs b/Content.Shared/Interaction/Events/InteractionFailureEvent.cs new file mode 100644 index 00000000000..a820048104d --- /dev/null +++ b/Content.Shared/Interaction/Events/InteractionFailureEvent.cs @@ -0,0 +1,7 @@ +namespace Content.Shared.Interaction.Events; + +/// +/// Raised on the target when failing to pet/hug something. +/// +[ByRefEvent] +public readonly record struct InteractionFailureEvent(EntityUid User); diff --git a/Content.Shared/Interaction/Events/InteractionSuccessEvent.cs b/Content.Shared/Interaction/Events/InteractionSuccessEvent.cs new file mode 100644 index 00000000000..da4f9e43d7d --- /dev/null +++ b/Content.Shared/Interaction/Events/InteractionSuccessEvent.cs @@ -0,0 +1,7 @@ +namespace Content.Shared.Interaction.Events; + +/// +/// Raised on the target when successfully petting/hugging something. +/// +[ByRefEvent] +public readonly record struct InteractionSuccessEvent(EntityUid User); diff --git a/Content.Shared/Interaction/InteractionPopupSystem.cs b/Content.Shared/Interaction/InteractionPopupSystem.cs index 2a742d4211b..20c079dfd8c 100644 --- a/Content.Shared/Interaction/InteractionPopupSystem.cs +++ b/Content.Shared/Interaction/InteractionPopupSystem.cs @@ -1,6 +1,7 @@ using Content.Shared.Bed.Sleep; using Content.Shared.IdentityManagement; using Content.Shared.Interaction.Components; +using Content.Shared.Interaction.Events; using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Systems; using Content.Shared.Popups; @@ -100,6 +101,9 @@ private void SharedInteract( if (component.InteractSuccessSpawn != null) Spawn(component.InteractSuccessSpawn, _transform.GetMapCoordinates(uid)); + + var ev = new InteractionSuccessEvent(user); + RaiseLocalEvent(target, ref ev); } else { @@ -111,6 +115,9 @@ private void SharedInteract( if (component.InteractFailureSpawn != null) Spawn(component.InteractFailureSpawn, _transform.GetMapCoordinates(uid)); + + var ev = new InteractionFailureEvent(user); + RaiseLocalEvent(target, ref ev); } if (!string.IsNullOrEmpty(component.MessagePerceivedByOthers)) From 2c9a3020ab866510f2ae19a16707f27e1e239288 Mon Sep 17 00:00:00 2001 From: deltanedas <39013340+deltanedas@users.noreply.github.com> Date: Wed, 18 Sep 2024 23:00:48 +0000 Subject: [PATCH 114/138] make epinephrine adrenaline (#32076) Co-authored-by: deltanedas <@deltanedas:kde.org> --- Resources/Prototypes/Reagents/medicine.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Resources/Prototypes/Reagents/medicine.yml b/Resources/Prototypes/Reagents/medicine.yml index 4dcef67f77d..105ae110487 100644 --- a/Resources/Prototypes/Reagents/medicine.yml +++ b/Resources/Prototypes/Reagents/medicine.yml @@ -359,6 +359,10 @@ key: KnockedDown time: 0.75 type: Remove + - !type:GenericStatusEffect + key: Adrenaline # Guess what epinephrine is... + component: IgnoreSlowOnDamage + time: 5 # lingers less than hivemind reagent to give it a niche - type: reagent id: Hyronalin From a8686b359779c3e2b22318a2a9234b02b489d9aa Mon Sep 17 00:00:00 2001 From: PJBot Date: Wed, 18 Sep 2024 23:01:54 +0000 Subject: [PATCH 115/138] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 9879e7f9a32..58776aa93c4 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Winkarst-cpu - changes: - - message: Fixed popup spam when trying to open borg's UI while the borg is locked. - type: Fix - id: 6893 - time: '2024-07-09T23:48:56.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29861 - author: Lokachop changes: - message: Scarves now count as warm clothing for the warm clothing cargo bounty. @@ -3917,3 +3910,10 @@ id: 7392 time: '2024-09-18T21:58:59.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/32144 +- author: deltanedas + changes: + - message: Epinephrine now adds Adrenaline, because it is. + type: Tweak + id: 7393 + time: '2024-09-18T23:00:48.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/32076 From d4a5bc8d6be87a90ee70db4530efa1a0864f177b Mon Sep 17 00:00:00 2001 From: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> Date: Wed, 18 Sep 2024 16:55:26 -0700 Subject: [PATCH 116/138] Fix unbuckling others when clicking on the strap entity (#29998) * Add failing unbuckle InteractHand test * Skip trybuckle if strap doesn't have space * Unbuckle others not just user * Fix test failing due to delay * Change to raise event instead of calling OnInteractHand * Add test for buckle and unbuckle on InteractHand * Add tick delay * Remove unneeded tick delay and clean up * Comment code * Cleanup * Swap to fastest checks first * Fix reading empty sequence when there are no buckled entities --- .../Tests/Buckle/BuckleTest.Interact.cs | 108 ++++++++++++++++++ .../Tests/Buckle/BuckleTest.cs | 2 +- .../Buckle/SharedBuckleSystem.Interaction.cs | 26 ++++- 3 files changed, 129 insertions(+), 7 deletions(-) create mode 100644 Content.IntegrationTests/Tests/Buckle/BuckleTest.Interact.cs diff --git a/Content.IntegrationTests/Tests/Buckle/BuckleTest.Interact.cs b/Content.IntegrationTests/Tests/Buckle/BuckleTest.Interact.cs new file mode 100644 index 00000000000..d9cce764ab7 --- /dev/null +++ b/Content.IntegrationTests/Tests/Buckle/BuckleTest.Interact.cs @@ -0,0 +1,108 @@ +using Content.Shared.Buckle; +using Content.Shared.Buckle.Components; +using Content.Shared.Interaction; +using Robust.Server.GameObjects; +using Robust.Shared.GameObjects; +using Robust.Shared.Map; + +namespace Content.IntegrationTests.Tests.Buckle; + +public sealed partial class BuckleTest +{ + [Test] + public async Task BuckleInteractUnbuckleOther() + { + await using var pair = await PoolManager.GetServerClient(); + var server = pair.Server; + + var entMan = server.ResolveDependency(); + var buckleSystem = entMan.System(); + + EntityUid user = default; + EntityUid victim = default; + EntityUid chair = default; + BuckleComponent buckle = null; + StrapComponent strap = null; + + await server.WaitAssertion(() => + { + user = entMan.SpawnEntity(BuckleDummyId, MapCoordinates.Nullspace); + victim = entMan.SpawnEntity(BuckleDummyId, MapCoordinates.Nullspace); + chair = entMan.SpawnEntity(StrapDummyId, MapCoordinates.Nullspace); + + Assert.That(entMan.TryGetComponent(victim, out buckle)); + Assert.That(entMan.TryGetComponent(chair, out strap)); + +#pragma warning disable RA0002 + buckle.Delay = TimeSpan.Zero; +#pragma warning restore RA0002 + + // Buckle victim to chair + Assert.That(buckleSystem.TryBuckle(victim, user, chair, buckle)); + Assert.Multiple(() => + { + Assert.That(buckle.BuckledTo, Is.EqualTo(chair), "Victim did not get buckled to the chair."); + Assert.That(buckle.Buckled, "Victim is not buckled."); + Assert.That(strap.BuckledEntities, Does.Contain(victim), "Chair does not have victim buckled to it."); + }); + + // InteractHand with chair to unbuckle victim + entMan.EventBus.RaiseLocalEvent(chair, new InteractHandEvent(user, chair)); + Assert.Multiple(() => + { + Assert.That(buckle.BuckledTo, Is.Null); + Assert.That(buckle.Buckled, Is.False); + Assert.That(strap.BuckledEntities, Does.Not.Contain(victim)); + }); + }); + + await pair.CleanReturnAsync(); + } + + [Test] + public async Task BuckleInteractBuckleUnbuckleSelf() + { + await using var pair = await PoolManager.GetServerClient(); + var server = pair.Server; + + var entMan = server.ResolveDependency(); + + EntityUid user = default; + EntityUid chair = default; + BuckleComponent buckle = null; + StrapComponent strap = null; + + await server.WaitAssertion(() => + { + user = entMan.SpawnEntity(BuckleDummyId, MapCoordinates.Nullspace); + chair = entMan.SpawnEntity(StrapDummyId, MapCoordinates.Nullspace); + + Assert.That(entMan.TryGetComponent(user, out buckle)); + Assert.That(entMan.TryGetComponent(chair, out strap)); + +#pragma warning disable RA0002 + buckle.Delay = TimeSpan.Zero; +#pragma warning restore RA0002 + + // Buckle user to chair + entMan.EventBus.RaiseLocalEvent(chair, new InteractHandEvent(user, chair)); + Assert.Multiple(() => + { + Assert.That(buckle.BuckledTo, Is.EqualTo(chair), "Victim did not get buckled to the chair."); + Assert.That(buckle.Buckled, "Victim is not buckled."); + Assert.That(strap.BuckledEntities, Does.Contain(user), "Chair does not have victim buckled to it."); + }); + + // InteractHand with chair to unbuckle + entMan.EventBus.RaiseLocalEvent(chair, new InteractHandEvent(user, chair)); + Assert.Multiple(() => + { + Assert.That(buckle.BuckledTo, Is.Null); + Assert.That(buckle.Buckled, Is.False); + Assert.That(strap.BuckledEntities, Does.Not.Contain(user)); + }); + }); + + await pair.CleanReturnAsync(); + } +} diff --git a/Content.IntegrationTests/Tests/Buckle/BuckleTest.cs b/Content.IntegrationTests/Tests/Buckle/BuckleTest.cs index 156f42aac33..1b31fe38c28 100644 --- a/Content.IntegrationTests/Tests/Buckle/BuckleTest.cs +++ b/Content.IntegrationTests/Tests/Buckle/BuckleTest.cs @@ -15,7 +15,7 @@ namespace Content.IntegrationTests.Tests.Buckle [TestFixture] [TestOf(typeof(BuckleComponent))] [TestOf(typeof(StrapComponent))] - public sealed class BuckleTest + public sealed partial class BuckleTest { private const string BuckleDummyId = "BuckleDummy"; private const string StrapDummyId = "StrapDummy"; diff --git a/Content.Shared/Buckle/SharedBuckleSystem.Interaction.cs b/Content.Shared/Buckle/SharedBuckleSystem.Interaction.cs index 7677e800fe9..1a15e52a3c4 100644 --- a/Content.Shared/Buckle/SharedBuckleSystem.Interaction.cs +++ b/Content.Shared/Buckle/SharedBuckleSystem.Interaction.cs @@ -1,5 +1,5 @@ +using System.Linq; using Content.Shared.Buckle.Components; -using Content.Shared.Cuffs.Components; using Content.Shared.DoAfter; using Content.Shared.DragDrop; using Content.Shared.IdentityManagement; @@ -84,15 +84,29 @@ private void OnStrapInteractHand(EntityUid uid, StrapComponent component, Intera if (!TryComp(args.User, out BuckleComponent? buckle)) return; - if (buckle.BuckledTo == null && component.BuckleOnInteractHand) + // Buckle self + if (buckle.BuckledTo == null && component.BuckleOnInteractHand && StrapHasSpace(uid, buckle, component)) + { TryBuckle(args.User, args.User, uid, buckle, popup: true); - else if (buckle.BuckledTo == uid) - TryUnbuckle(args.User, args.User, buckle, popup: true); - else + args.Handled = true; + return; + } + + // Unbuckle self + if (buckle.BuckledTo == uid && TryUnbuckle(args.User, args.User, buckle, popup: true)) + { + args.Handled = true; return; + } + + // Unbuckle others + if (component.BuckledEntities.TryFirstOrNull(out var buckled) && TryUnbuckle(buckled.Value, args.User)) + { + args.Handled = true; + return; + } // TODO BUCKLE add out bool for whether a pop-up was generated or not. - args.Handled = true; } private void OnBuckleInteractHand(Entity ent, ref InteractHandEvent args) From 7ceb2d250799474c6c627121a0cfde7bf90379d4 Mon Sep 17 00:00:00 2001 From: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> Date: Wed, 18 Sep 2024 16:55:53 -0700 Subject: [PATCH 117/138] Add a method to get the first available ItemSlot (#29846) * Add a method to get the first available ItemSlot * Make TryInsertEmpty use TryGetAvailableSlot * Add param doc comments --- .../Containers/ItemSlot/ItemSlotsSystem.cs | 69 ++++++++++++++----- 1 file changed, 53 insertions(+), 16 deletions(-) diff --git a/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs b/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs index f41fa2b22d2..f25273f4039 100644 --- a/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs +++ b/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs @@ -359,39 +359,76 @@ public bool TryInsertFromHand(EntityUid uid, ItemSlot slot, EntityUid user, Hand /// Useful for predicted interactions /// /// False if failed to insert item - public bool TryInsertEmpty(Entity ent, EntityUid item, EntityUid? user, bool excludeUserAudio = false) + public bool TryInsertEmpty(Entity ent, + EntityUid item, + EntityUid? user, + bool excludeUserAudio = false) { + if (!Resolve(ent, ref ent.Comp, false)) + return false; + + TryComp(user, out HandsComponent? handsComp); + + if (!TryGetAvailableSlot(ent, + item, + user == null ? null : (user.Value, handsComp), + out var itemSlot, + emptyOnly: true)) + return false; + + if (user != null && !_handsSystem.TryDrop(user.Value, item, handsComp: handsComp)) + return false; + + Insert(ent, itemSlot, item, user, excludeUserAudio: excludeUserAudio); + return true; + } + + /// + /// Tries to get any slot that the can be inserted into. + /// + /// Entity that is being inserted into. + /// Entity being inserted into . + /// Entity inserting into . + /// The ItemSlot on to insert into. + /// True only returns slots that are empty. + /// False returns any slot that is able to receive . + /// True when a slot is found. Otherwise, false. + public bool TryGetAvailableSlot(Entity ent, + EntityUid item, + Entity? userEnt, + [NotNullWhen(true)] out ItemSlot? itemSlot, + bool emptyOnly = false) + { + itemSlot = null; + + if (userEnt is { } user + && Resolve(user, ref user.Comp) + && _handsSystem.IsHolding(user, item)) + { + if (!_handsSystem.CanDrop(user, item, user.Comp)) + return false; + } + if (!Resolve(ent, ref ent.Comp, false)) return false; var slots = new List(); foreach (var slot in ent.Comp.Slots.Values) { - if (slot.ContainerSlot?.ContainedEntity != null) + if (emptyOnly && slot.ContainerSlot?.ContainedEntity != null) continue; - if (CanInsert(ent, item, user, slot)) + if (CanInsert(ent, item, userEnt, slot)) slots.Add(slot); } if (slots.Count == 0) return false; - if (user != null && _handsSystem.IsHolding(user.Value, item)) - { - if (!_handsSystem.TryDrop(user.Value, item)) - return false; - } - slots.Sort(SortEmpty); - foreach (var slot in slots) - { - if (TryInsert(ent, slot, item, user, excludeUserAudio: excludeUserAudio)) - return true; - } - - return false; + itemSlot = slots[0]; + return true; } private static int SortEmpty(ItemSlot a, ItemSlot b) From e6e166405d1008db374363d41d78459330d9f19f Mon Sep 17 00:00:00 2001 From: PJBot Date: Wed, 18 Sep 2024 23:56:32 +0000 Subject: [PATCH 118/138] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 58776aa93c4..8190ecd8fe4 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Lokachop - changes: - - message: Scarves now count as warm clothing for the warm clothing cargo bounty. - type: Tweak - id: 6894 - time: '2024-07-10T05:26:33.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29779 - author: Aquif changes: - message: It is now possible to "lock" admin faxes such that they cannot be edited @@ -3917,3 +3910,11 @@ id: 7393 time: '2024-09-18T23:00:48.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/32076 +- author: ShadowCommander + changes: + - message: Fixed clicking on chairs and beds with an entity buckled to them not + unbuckling them. + type: Fix + id: 7394 + time: '2024-09-18T23:55:26.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29998 From 84062da1289b760ee8714239322ae07b74e6187c Mon Sep 17 00:00:00 2001 From: deltanedas <39013340+deltanedas@users.noreply.github.com> Date: Wed, 18 Sep 2024 23:58:10 +0000 Subject: [PATCH 119/138] let FlashArea be called from shared (#30343) * let FlashArea be called from shared * untroll --------- Co-authored-by: deltanedas <@deltanedas:kde.org> Co-authored-by: metalgearsloth --- Content.Client/Flash/FlashOverlay.cs | 4 +++- Content.Server/Flash/FlashSystem.cs | 2 +- Content.Shared/Flash/SharedFlashSystem.cs | 13 +++++++++---- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/Content.Client/Flash/FlashOverlay.cs b/Content.Client/Flash/FlashOverlay.cs index 046be2aa621..8e41c382dd7 100644 --- a/Content.Client/Flash/FlashOverlay.cs +++ b/Content.Client/Flash/FlashOverlay.cs @@ -16,6 +16,7 @@ public sealed class FlashOverlay : Overlay [Dependency] private readonly IPlayerManager _playerManager = default!; [Dependency] private readonly IGameTiming _timing = default!; + private readonly SharedFlashSystem _flash; private readonly StatusEffectsSystem _statusSys; public override OverlaySpace Space => OverlaySpace.WorldSpace; @@ -27,6 +28,7 @@ public FlashOverlay() { IoCManager.InjectDependencies(this); _shader = _prototypeManager.Index("FlashedEffect").InstanceUnique(); + _flash = _entityManager.System(); _statusSys = _entityManager.System(); } @@ -41,7 +43,7 @@ protected override void FrameUpdate(FrameEventArgs args) || !_entityManager.TryGetComponent(playerEntity, out var status)) return; - if (!_statusSys.TryGetTime(playerEntity.Value, SharedFlashSystem.FlashedKey, out var time, status)) + if (!_statusSys.TryGetTime(playerEntity.Value, _flash.FlashedKey, out var time, status)) return; var curTime = _timing.CurTime; diff --git a/Content.Server/Flash/FlashSystem.cs b/Content.Server/Flash/FlashSystem.cs index ccb58e94f81..fb449a372cd 100644 --- a/Content.Server/Flash/FlashSystem.cs +++ b/Content.Server/Flash/FlashSystem.cs @@ -152,7 +152,7 @@ public void Flash(EntityUid target, } } - public void FlashArea(Entity source, EntityUid? user, float range, float duration, float slowTo = 0.8f, bool displayPopup = false, float probability = 1f, SoundSpecifier? sound = null) + public override void FlashArea(Entity source, EntityUid? user, float range, float duration, float slowTo = 0.8f, bool displayPopup = false, float probability = 1f, SoundSpecifier? sound = null) { var transform = Transform(source); var mapPosition = _transform.GetMapCoordinates(transform); diff --git a/Content.Shared/Flash/SharedFlashSystem.cs b/Content.Shared/Flash/SharedFlashSystem.cs index f83f02a3105..b7788098870 100644 --- a/Content.Shared/Flash/SharedFlashSystem.cs +++ b/Content.Shared/Flash/SharedFlashSystem.cs @@ -1,10 +1,15 @@ +using Content.Shared.Flash.Components; using Content.Shared.StatusEffect; +using Robust.Shared.Audio; +using Robust.Shared.Prototypes; -namespace Content.Shared.Flash +namespace Content.Shared.Flash; + +public abstract class SharedFlashSystem : EntitySystem { - public abstract class SharedFlashSystem : EntitySystem + public ProtoId FlashedKey = "Flashed"; + + public virtual void FlashArea(Entity source, EntityUid? user, float range, float duration, float slowTo = 0.8f, bool displayPopup = false, float probability = 1f, SoundSpecifier? sound = null) { - [ValidatePrototypeId] - public const string FlashedKey = "Flashed"; } } From 1c839da60496f4a3171c7f959a88effe4aeff5a8 Mon Sep 17 00:00:00 2001 From: deltanedas <39013340+deltanedas@users.noreply.github.com> Date: Thu, 19 Sep 2024 00:01:40 +0000 Subject: [PATCH 120/138] move TriggerExplosion to shared (#30227) * move component to shared * add fake systems * update server explosion system and remove duplicate transform query --------- Co-authored-by: deltanedas <@deltanedas:kde.org> --- Content.Client/Explosion/ExplosionSystem.cs | 5 +-- .../Behaviors/SolutionExplosionBehavior.cs | 2 +- .../EntitySystems/ExplosionSystem.Airtight.cs | 3 +- .../EntitySystems/ExplosionSystem.CVars.cs | 4 +-- .../EntitySystems/ExplosionSystem.GridMap.cs | 2 +- .../ExplosionSystem.Processing.cs | 7 ++-- .../EntitySystems/ExplosionSystem.TileFill.cs | 4 +-- .../EntitySystems/ExplosionSystem.Visuals.cs | 3 +- .../EntitySystems/ExplosionSystem.cs | 15 +++----- .../Components/ExplosiveComponent.cs | 35 +++++++------------ .../EntitySystems/SharedExplosionSystem.cs | 25 ++++++++++--- 11 files changed, 52 insertions(+), 53 deletions(-) rename {Content.Server => Content.Shared}/Explosion/Components/ExplosiveComponent.cs (76%) diff --git a/Content.Client/Explosion/ExplosionSystem.cs b/Content.Client/Explosion/ExplosionSystem.cs index a2ed2d50e0d..692782ded4b 100644 --- a/Content.Client/Explosion/ExplosionSystem.cs +++ b/Content.Client/Explosion/ExplosionSystem.cs @@ -2,7 +2,4 @@ namespace Content.Client.Explosion.EntitySystems; -public sealed class ExplosionSystem : SharedExplosionSystem -{ - -} +public sealed class ExplosionSystem : SharedExplosionSystem; diff --git a/Content.Server/Destructible/Thresholds/Behaviors/SolutionExplosionBehavior.cs b/Content.Server/Destructible/Thresholds/Behaviors/SolutionExplosionBehavior.cs index 5166aaccabb..08c7c8f068f 100644 --- a/Content.Server/Destructible/Thresholds/Behaviors/SolutionExplosionBehavior.cs +++ b/Content.Server/Destructible/Thresholds/Behaviors/SolutionExplosionBehavior.cs @@ -1,4 +1,4 @@ -using Content.Server.Explosion.Components; +using Content.Shared.Explosion.Components; using JetBrains.Annotations; namespace Content.Server.Destructible.Thresholds.Behaviors diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Airtight.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Airtight.cs index 4b59c8f1c48..6fa553bc8b6 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Airtight.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Airtight.cs @@ -6,9 +6,10 @@ using Content.Shared.Explosion.EntitySystems; using Content.Shared.FixedPoint; using Robust.Shared.Map.Components; + namespace Content.Server.Explosion.EntitySystems; -public sealed partial class ExplosionSystem : SharedExplosionSystem +public sealed partial class ExplosionSystem { [Dependency] private readonly DestructibleSystem _destructibleSystem = default!; diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.CVars.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.CVars.cs index ce98f89de7a..5af06ef9368 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.CVars.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.CVars.cs @@ -1,8 +1,8 @@ using Content.Shared.CCVar; -using Content.Shared.Explosion.EntitySystems; + namespace Content.Server.Explosion.EntitySystems; -public sealed partial class ExplosionSystem : SharedExplosionSystem +public sealed partial class ExplosionSystem { public int MaxIterations { get; private set; } public int MaxArea { get; private set; } diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.GridMap.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.GridMap.cs index 75bb606441a..29477c16b28 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.GridMap.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.GridMap.cs @@ -12,7 +12,7 @@ namespace Content.Server.Explosion.EntitySystems; // A good portion of it is focused around keeping track of what tile-indices on a grid correspond to tiles that border // space. AFAIK no other system currently needs to track these "edge-tiles". If they do, this should probably be a // property of the grid itself? -public sealed partial class ExplosionSystem : SharedExplosionSystem +public sealed partial class ExplosionSystem { /// /// Set of tiles of each grid that are directly adjacent to space, along with the directions that face space. diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs index 6d0cbcf2794..97d52e436a8 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs @@ -22,9 +22,10 @@ using Robust.Shared.Timing; using Robust.Shared.Utility; using TimedDespawnComponent = Robust.Shared.Spawners.TimedDespawnComponent; + namespace Content.Server.Explosion.EntitySystems; -public sealed partial class ExplosionSystem : SharedExplosionSystem +public sealed partial class ExplosionSystem { [Dependency] private readonly FlammableSystem _flammableSystem = default!; @@ -218,7 +219,7 @@ internal bool ExplodeTile(BroadphaseComponent lookup, // get the entities on a tile. Note that we cannot process them directly, or we get // enumerator-changed-while-enumerating errors. List<(EntityUid, TransformComponent)> list = new(); - var state = (list, processed, _transformQuery); + var state = (list, processed, EntityManager.TransformQuery); // get entities: lookup.DynamicTree.QueryAabb(ref state, GridQueryCallback, gridBox, true); @@ -317,7 +318,7 @@ internal void ExplodeSpace(BroadphaseComponent lookup, var gridBox = Box2.FromDimensions(tile * DefaultTileSize, new Vector2(DefaultTileSize, DefaultTileSize)); var worldBox = spaceMatrix.TransformBox(gridBox); var list = new List<(EntityUid, TransformComponent)>(); - var state = (list, processed, invSpaceMatrix, lookup.Owner, _transformQuery, gridBox, _transformSystem); + var state = (list, processed, invSpaceMatrix, lookup.Owner, EntityManager.TransformQuery, gridBox, _transformSystem); // get entities: lookup.DynamicTree.QueryAabb(ref state, SpaceQueryCallback, worldBox, true); diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.TileFill.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.TileFill.cs index 8c3229e06ee..7b73490d946 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.TileFill.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.TileFill.cs @@ -7,13 +7,13 @@ using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; using Robust.Shared.Timing; -using Content.Shared.Explosion.EntitySystems; + namespace Content.Server.Explosion.EntitySystems; // This partial part of the explosion system has all of the functions used to create the actual explosion map. // I.e, to get the sets of tiles & intensity values that describe an explosion. -public sealed partial class ExplosionSystem : SharedExplosionSystem +public sealed partial class ExplosionSystem { /// /// This is the main explosion generating function. diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Visuals.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Visuals.cs index 219dba4bdeb..57323e4de70 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Visuals.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Visuals.cs @@ -5,10 +5,11 @@ using Robust.Server.GameObjects; using Robust.Shared.GameStates; using Robust.Shared.Map; + namespace Content.Server.Explosion.EntitySystems; // This part of the system handled send visual / overlay data to clients. -public sealed partial class ExplosionSystem : SharedExplosionSystem +public sealed partial class ExplosionSystem { public void InitVisuals() { diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs index cd0ca1c22eb..818953ed4b4 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs @@ -12,6 +12,8 @@ using Content.Shared.Damage; using Content.Shared.Database; using Content.Shared.Explosion; +using Content.Shared.Explosion.Components; +using Content.Shared.Explosion.EntitySystems; using Content.Shared.GameTicking; using Content.Shared.Inventory; using Content.Shared.Projectiles; @@ -53,7 +55,6 @@ public sealed partial class ExplosionSystem : SharedExplosionSystem [Dependency] private readonly SharedTransformSystem _transformSystem = default!; [Dependency] private readonly SharedMapSystem _map = default!; - private EntityQuery _transformQuery; private EntityQuery _flammableQuery; private EntityQuery _physicsQuery; private EntityQuery _projectileQuery; @@ -103,7 +104,6 @@ public override void Initialize() InitAirtightMap(); InitVisuals(); - _transformQuery = GetEntityQuery(); _flammableQuery = GetEntityQuery(); _physicsQuery = GetEntityQuery(); _projectileQuery = GetEntityQuery(); @@ -141,15 +141,8 @@ private void OnGetResistance(EntityUid uid, ExplosionResistanceComponent compone args.DamageCoefficient *= modifier; } - /// - /// Given an entity with an explosive component, spawn the appropriate explosion. - /// - /// - /// Also accepts radius or intensity arguments. This is useful for explosives where the intensity is not - /// specified in the yaml / by the component, but determined dynamically (e.g., by the quantity of a - /// solution in a reaction). - /// - public void TriggerExplosive(EntityUid uid, ExplosiveComponent? explosive = null, bool delete = true, float? totalIntensity = null, float? radius = null, EntityUid? user = null) + /// + public override void TriggerExplosive(EntityUid uid, ExplosiveComponent? explosive = null, bool delete = true, float? totalIntensity = null, float? radius = null, EntityUid? user = null) { // log missing: false, because some entities (e.g. liquid tanks) attempt to trigger explosions when damaged, // but may not actually be explosive. diff --git a/Content.Server/Explosion/Components/ExplosiveComponent.cs b/Content.Shared/Explosion/Components/ExplosiveComponent.cs similarity index 76% rename from Content.Server/Explosion/Components/ExplosiveComponent.cs rename to Content.Shared/Explosion/Components/ExplosiveComponent.cs index 2b27a89d9db..bab7f5a7d67 100644 --- a/Content.Server/Explosion/Components/ExplosiveComponent.cs +++ b/Content.Shared/Explosion/Components/ExplosiveComponent.cs @@ -1,8 +1,7 @@ -using Content.Server.Explosion.EntitySystems; -using Content.Shared.Explosion; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; +using Content.Shared.Explosion.EntitySystems; +using Robust.Shared.Prototypes; -namespace Content.Server.Explosion.Components; +namespace Content.Shared.Explosion.Components; /// /// Specifies an explosion that can be spawned by this entity. The explosion itself is spawned via -[RegisterComponent] +[RegisterComponent, Access(typeof(SharedExplosionSystem))] public sealed partial class ExplosiveComponent : Component { - /// /// The explosion prototype. This determines the damage types, the tile-break chance, and some visual /// information (e.g., the light that the explosion gives off). /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("explosionType", required: true, customTypeSerializer: typeof(PrototypeIdSerializer))] - public string ExplosionType = default!; + [DataField(required: true)] + public ProtoId ExplosionType = default!; /// /// The maximum intensity the explosion can have on a single tile. This limits the maximum damage and tile /// break chance the explosion can achieve at any given location. /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("maxIntensity")] + [DataField] public float MaxIntensity = 4; /// /// How quickly the intensity drops off as you move away from the epicenter. /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("intensitySlope")] + [DataField] public float IntensitySlope = 1; /// @@ -47,38 +42,34 @@ public sealed partial class ExplosiveComponent : Component /// This number can be overridden by passing optional argument to . /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("totalIntensity")] + [DataField] public float TotalIntensity = 10; /// /// Factor used to scale the explosion intensity when calculating tile break chances. Allows for stronger /// explosives that don't space tiles, without having to create a new explosion-type prototype. /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("tileBreakScale")] + [DataField] public float TileBreakScale = 1f; /// /// Maximum number of times that an explosive can break a tile. Currently, for normal space stations breaking a /// tile twice will generally result in a vacuum. /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("maxTileBreak")] + [DataField] public int MaxTileBreak = int.MaxValue; /// /// Whether this explosive should be able to create a vacuum by breaking tiles. /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("canCreateVacuum")] + [DataField] public bool CanCreateVacuum = true; /// /// An override for whether or not the entity should be deleted after it explodes. /// If null, the system calling the explode method handles it. /// - [DataField("deleteAfterExplosion")] + [DataField] public bool? DeleteAfterExplosion; /// diff --git a/Content.Shared/Explosion/EntitySystems/SharedExplosionSystem.cs b/Content.Shared/Explosion/EntitySystems/SharedExplosionSystem.cs index 1d926dd0b67..f2982558078 100644 --- a/Content.Shared/Explosion/EntitySystems/SharedExplosionSystem.cs +++ b/Content.Shared/Explosion/EntitySystems/SharedExplosionSystem.cs @@ -1,25 +1,40 @@ -using Content.Shared.Explosion.Components; using Content.Shared.Armor; +using Content.Shared.Explosion.Components; namespace Content.Shared.Explosion.EntitySystems; +/// +/// Lets code in shared trigger explosions and handles explosion resistance examining. +/// All processing is still done clientside. +/// public abstract class SharedExplosionSystem : EntitySystem { - public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnArmorExamine); } - private void OnArmorExamine(EntityUid uid, ExplosionResistanceComponent component, ref ArmorExamineEvent args) + private void OnArmorExamine(Entity ent, ref ArmorExamineEvent args) { - var value = MathF.Round((1f - component.DamageCoefficient) * 100, 1); + var value = MathF.Round((1f - ent.Comp.DamageCoefficient) * 100, 1); if (value == 0) return; args.Msg.PushNewline(); - args.Msg.AddMarkupOrThrow(Loc.GetString(component.Examine, ("value", value))); + args.Msg.AddMarkupOrThrow(Loc.GetString(ent.Comp.Examine, ("value", value))); + } + + /// + /// Given an entity with an explosive component, spawn the appropriate explosion. + /// + /// + /// Also accepts radius or intensity arguments. This is useful for explosives where the intensity is not + /// specified in the yaml / by the component, but determined dynamically (e.g., by the quantity of a + /// solution in a reaction). + /// + public virtual void TriggerExplosive(EntityUid uid, ExplosiveComponent? explosive = null, bool delete = true, float? totalIntensity = null, float? radius = null, EntityUid? user = null) + { } } From 4f77709eed9b5012e58303820eafb0242a0f36fd Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Thu, 19 Sep 2024 10:02:27 +1000 Subject: [PATCH 121/138] Add flip button to mapping state (#30636) --- Content.Client/Mapping/MappingScreen.xaml | 1 + Content.Client/Mapping/MappingScreen.xaml.cs | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/Content.Client/Mapping/MappingScreen.xaml b/Content.Client/Mapping/MappingScreen.xaml index b6413608478..9cc3e734f0e 100644 --- a/Content.Client/Mapping/MappingScreen.xaml +++ b/Content.Client/Mapping/MappingScreen.xaml @@ -78,6 +78,7 @@ ToolTip="Pick (Hold 5)" /> + diff --git a/Content.Client/Mapping/MappingScreen.xaml.cs b/Content.Client/Mapping/MappingScreen.xaml.cs index b2ad2fd83fb..46c0e51fad6 100644 --- a/Content.Client/Mapping/MappingScreen.xaml.cs +++ b/Content.Client/Mapping/MappingScreen.xaml.cs @@ -96,6 +96,22 @@ public MappingScreen() Pick.Texture.TexturePath = "/Textures/Interface/eyedropper.svg.png"; Delete.Texture.TexturePath = "/Textures/Interface/eraser.svg.png"; + Flip.Texture.TexturePath = "/Textures/Interface/VerbIcons/rotate_cw.svg.192dpi.png"; + Flip.OnPressed += args => FlipSides(); + } + + public void FlipSides() + { + ScreenContainer.Flip(); + + if (SpawnContainer.GetPositionInParent() == 0) + { + Flip.Texture.TexturePath = "/Textures/Interface/VerbIcons/rotate_cw.svg.192dpi.png"; + } + else + { + Flip.Texture.TexturePath = "/Textures/Interface/VerbIcons/rotate_ccw.svg.192dpi.png"; + } } private void OnDecalColorPicked(Color color) From 6958789f37db66d54a8c68f6d04d997c8f1650ab Mon Sep 17 00:00:00 2001 From: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> Date: Wed, 18 Sep 2024 17:08:37 -0700 Subject: [PATCH 122/138] Give prototype refactor (#29697) * Update GivePrototype * File scoped namespace * Change to EntProtoId instead of ProtoId<> for better validation --- .../Construction/Completions/GivePrototype.cs | 54 ++++++++++--------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/Content.Server/Construction/Completions/GivePrototype.cs b/Content.Server/Construction/Completions/GivePrototype.cs index f45bd5ba105..f05feb70c03 100644 --- a/Content.Server/Construction/Completions/GivePrototype.cs +++ b/Content.Server/Construction/Completions/GivePrototype.cs @@ -1,44 +1,50 @@ using Content.Server.Stack; using Content.Shared.Construction; +using Content.Shared.Hands.Components; using Content.Shared.Hands.EntitySystems; using Content.Shared.Prototypes; using Content.Shared.Stacks; using JetBrains.Annotations; using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -namespace Content.Server.Construction.Completions +namespace Content.Server.Construction.Completions; + +[UsedImplicitly] +[DataDefinition] +public sealed partial class GivePrototype : IGraphAction { - [UsedImplicitly] - [DataDefinition] - public sealed partial class GivePrototype : IGraphAction + [DataField] + public EntProtoId Prototype { get; private set; } = string.Empty; + + [DataField] + public int Amount { get; private set; } = 1; + + public void PerformAction(EntityUid uid, EntityUid? userUid, IEntityManager entityManager) { - [DataField("prototype", customTypeSerializer:typeof(PrototypeIdSerializer))] - public string Prototype { get; private set; } = string.Empty; - [DataField("amount")] - public int Amount { get; private set; } = 1; + if (string.IsNullOrEmpty(Prototype)) + return; - public void PerformAction(EntityUid uid, EntityUid? userUid, IEntityManager entityManager) + if (EntityPrototypeHelpers.HasComponent(Prototype)) { - if (string.IsNullOrEmpty(Prototype)) - return; + var stackSystem = entityManager.EntitySysManager.GetEntitySystem(); + var stacks = stackSystem.SpawnMultiple(Prototype, Amount, userUid ?? uid); - var coordinates = entityManager.GetComponent(userUid ?? uid).Coordinates; + if (userUid is null || !entityManager.TryGetComponent(userUid, out HandsComponent? handsComp)) + return; - if (EntityPrototypeHelpers.HasComponent(Prototype)) + foreach (var item in stacks) { - var stackEnt = entityManager.SpawnEntity(Prototype, coordinates); - var stack = entityManager.GetComponent(stackEnt); - entityManager.EntitySysManager.GetEntitySystem().SetCount(stackEnt, Amount, stack); - entityManager.EntitySysManager.GetEntitySystem().PickupOrDrop(userUid, stackEnt); + stackSystem.TryMergeToHands(item, userUid.Value, hands: handsComp); } - else + } + else + { + var handsSystem = entityManager.EntitySysManager.GetEntitySystem(); + var handsComp = userUid is not null ? entityManager.GetComponent(userUid.Value) : null; + for (var i = 0; i < Amount; i++) { - for (var i = 0; i < Amount; i++) - { - var item = entityManager.SpawnEntity(Prototype, coordinates); - entityManager.EntitySysManager.GetEntitySystem().PickupOrDrop(userUid, item); - } + var item = entityManager.SpawnNextToOrDrop(Prototype, userUid ?? uid); + handsSystem.PickupOrDrop(userUid, item, handsComp: handsComp); } } } From cc7e5e01508b6ac79d6e85b18ec4ec7bc839ec71 Mon Sep 17 00:00:00 2001 From: SlamBamActionman <83650252+SlamBamActionman@users.noreply.github.com> Date: Thu, 19 Sep 2024 02:14:29 +0200 Subject: [PATCH 123/138] Allow containment field generators to be enabled on mapinit (#31158) * Initial commit * review fix --- .../EntitySystems/ContainmentFieldGeneratorSystem.cs | 7 +++++++ .../Components/ContainmentFieldGeneratorComponent.cs | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Content.Server/Singularity/EntitySystems/ContainmentFieldGeneratorSystem.cs b/Content.Server/Singularity/EntitySystems/ContainmentFieldGeneratorSystem.cs index 05262f29996..6d97c8ccb3d 100644 --- a/Content.Server/Singularity/EntitySystems/ContainmentFieldGeneratorSystem.cs +++ b/Content.Server/Singularity/EntitySystems/ContainmentFieldGeneratorSystem.cs @@ -37,6 +37,7 @@ public override void Initialize() SubscribeLocalEvent(OnUnanchorAttempt); SubscribeLocalEvent(OnComponentRemoved); SubscribeLocalEvent(PreventBreach); + SubscribeLocalEvent(OnMapInit); } public override void Update(float frameTime) @@ -61,6 +62,12 @@ public override void Update(float frameTime) #region Events + private void OnMapInit(Entity generator, ref MapInitEvent args) + { + if (generator.Comp.Enabled) + ChangeFieldVisualizer(generator); + } + /// /// A generator receives power from a source colliding with it. /// diff --git a/Content.Shared/Singularity/Components/ContainmentFieldGeneratorComponent.cs b/Content.Shared/Singularity/Components/ContainmentFieldGeneratorComponent.cs index 938b34f354a..6b09edfa1f0 100644 --- a/Content.Shared/Singularity/Components/ContainmentFieldGeneratorComponent.cs +++ b/Content.Shared/Singularity/Components/ContainmentFieldGeneratorComponent.cs @@ -79,7 +79,7 @@ public int PowerBuffer /// /// Is the generator toggled on? /// - [ViewVariables] + [DataField] public bool Enabled; /// From c2a201d998830b36fa525c5ee9bb1375bf41d732 Mon Sep 17 00:00:00 2001 From: Winkarst <74284083+Winkarst-cpu@users.noreply.github.com> Date: Thu, 19 Sep 2024 03:23:50 +0300 Subject: [PATCH 124/138] Make fire leave burnt decals on the tiles (#31939) * Make fire leave burnt decals on the tiles * License * Yes * Update * Spelling error * Prototypes reload support * To array --- .../EntitySystems/AtmosphereSystem.Hotspot.cs | 33 +++++++++++++++--- .../Atmos/EntitySystems/AtmosphereSystem.cs | 19 ++++++++++ Resources/Prototypes/Decals/burnt.yml | 31 ++++++++++++++++ .../Textures/Decals/burnt.rsi/burnt1.png | Bin 0 -> 896 bytes .../Textures/Decals/burnt.rsi/burnt2.png | Bin 0 -> 938 bytes .../Textures/Decals/burnt.rsi/burnt3.png | Bin 0 -> 928 bytes .../Textures/Decals/burnt.rsi/burnt4.png | Bin 0 -> 1041 bytes Resources/Textures/Decals/burnt.rsi/meta.json | 27 ++++++++++++++ 8 files changed, 106 insertions(+), 4 deletions(-) create mode 100644 Resources/Prototypes/Decals/burnt.yml create mode 100644 Resources/Textures/Decals/burnt.rsi/burnt1.png create mode 100644 Resources/Textures/Decals/burnt.rsi/burnt2.png create mode 100644 Resources/Textures/Decals/burnt.rsi/burnt3.png create mode 100644 Resources/Textures/Decals/burnt.rsi/burnt4.png create mode 100644 Resources/Textures/Decals/burnt.rsi/meta.json diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs index db952237338..a03f27b561a 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs @@ -1,19 +1,21 @@ using Content.Server.Atmos.Components; -using Content.Server.Atmos.Reactions; +using Content.Server.Decals; using Content.Shared.Atmos; using Content.Shared.Atmos.Components; using Content.Shared.Atmos.Reactions; -using Content.Shared.Audio; using Content.Shared.Database; using Robust.Shared.Audio; using Robust.Shared.Map; using Robust.Shared.Map.Components; -using Robust.Shared.Player; +using Robust.Shared.Random; namespace Content.Server.Atmos.EntitySystems { public sealed partial class AtmosphereSystem { + [Dependency] private readonly DecalSystem _decalSystem = default!; + [Dependency] private readonly IRobustRandom _random = default!; + private const int HotspotSoundCooldownCycles = 200; private int _hotspotSoundCooldown = 0; @@ -56,7 +58,30 @@ private void ProcessHotspot( if (tile.Hotspot.Bypassing) { tile.Hotspot.State = 3; - // TODO ATMOS: Burn tile here + + var gridUid = ent.Owner; + var tilePos = tile.GridIndices; + + // Get the existing decals on the tile + var tileDecals = _decalSystem.GetDecalsInRange(gridUid, tilePos); + + // Count the burnt decals on the tile + var tileBurntDecals = 0; + + foreach (var set in tileDecals) + { + if (Array.IndexOf(_burntDecals, set.Decal.Id) == -1) + continue; + + tileBurntDecals++; + + if (tileBurntDecals > 4) + break; + } + + // Add a random burned decal to the tile only if there are less than 4 of them + if (tileBurntDecals < 4) + _decalSystem.TryAddDecal(_burntDecals[_random.Next(_burntDecals.Length)], new EntityCoordinates(gridUid, tilePos), out _, cleanable: true); if (tile.Air.Temperature > Atmospherics.FireMinimumTemperatureToSpread) { diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs index 44bfa4cc10c..13d8f73dc56 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs @@ -4,6 +4,7 @@ using Content.Server.Fluids.EntitySystems; using Content.Server.NodeContainer.EntitySystems; using Content.Shared.Atmos.EntitySystems; +using Content.Shared.Decals; using Content.Shared.Doors.Components; using Content.Shared.Maps; using JetBrains.Annotations; @@ -12,7 +13,9 @@ using Robust.Shared.Containers; using Robust.Shared.Map; using Robust.Shared.Physics.Systems; +using Robust.Shared.Prototypes; using Robust.Shared.Random; +using System.Linq; namespace Content.Server.Atmos.EntitySystems; @@ -36,6 +39,7 @@ public sealed partial class AtmosphereSystem : SharedAtmosphereSystem [Dependency] private readonly SharedTransformSystem _transformSystem = default!; [Dependency] private readonly TileSystem _tile = default!; [Dependency] private readonly MapSystem _map = default!; + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] public readonly PuddleSystem Puddle = default!; private const float ExposedUpdateDelay = 1f; @@ -47,6 +51,8 @@ public sealed partial class AtmosphereSystem : SharedAtmosphereSystem private EntityQuery _firelockQuery; private HashSet _entSet = new(); + private string[] _burntDecals = []; + public override void Initialize() { base.Initialize(); @@ -66,7 +72,9 @@ public override void Initialize() _firelockQuery = GetEntityQuery(); SubscribeLocalEvent(OnTileChanged); + SubscribeLocalEvent(OnPrototypesReloaded); + CacheDecals(); } public override void Shutdown() @@ -81,6 +89,12 @@ private void OnTileChanged(ref TileChangedEvent ev) InvalidateTile(ev.NewTile.GridUid, ev.NewTile.GridIndices); } + private void OnPrototypesReloaded(PrototypesReloadedEventArgs ev) + { + if (ev.WasModified()) + CacheDecals(); + } + public override void Update(float frameTime) { base.Update(frameTime); @@ -107,4 +121,9 @@ public override void Update(float frameTime) _exposedTimer -= ExposedUpdateDelay; } + + private void CacheDecals() + { + _burntDecals = _prototypeManager.EnumeratePrototypes().Where(x => x.Tags.Contains("burnt")).Select(x => x.ID).ToArray(); + } } diff --git a/Resources/Prototypes/Decals/burnt.yml b/Resources/Prototypes/Decals/burnt.yml new file mode 100644 index 00000000000..d9d500e1aa2 --- /dev/null +++ b/Resources/Prototypes/Decals/burnt.yml @@ -0,0 +1,31 @@ +- type: decal + id: burnt1 + tags: ["burnt"] + defaultCleanable: true + sprite: + sprite: Decals/burnt.rsi + state: burnt1 + +- type: decal + id: burnt2 + tags: ["burnt"] + defaultCleanable: true + sprite: + sprite: Decals/burnt.rsi + state: burnt2 + +- type: decal + id: burnt3 + tags: ["burnt"] + defaultCleanable: true + sprite: + sprite: Decals/burnt.rsi + state: burnt3 + +- type: decal + id: burnt4 + tags: ["burnt"] + defaultCleanable: true + sprite: + sprite: Decals/burnt.rsi + state: burnt4 diff --git a/Resources/Textures/Decals/burnt.rsi/burnt1.png b/Resources/Textures/Decals/burnt.rsi/burnt1.png new file mode 100644 index 0000000000000000000000000000000000000000..3fcb7a4949b5bd561e68d784d47d9de20a5411d2 GIT binary patch literal 896 zcmV-`1AqL9P)_`sikSPhHe~3@fwDqi`!27YaPdN z#XAQ{Mbb&qIqVecW=VHRx3Ec4r4L^n0fb{a_q`;oVHMzdNk>T+Sc&%@lCF||0?2Ft z@TYMc*YYNKA9lck1x~sM{t=mf#{D6J5x9NYmwnV>7*yT_FA<=R=W95g?Z)O zXSr#2Y=Ql?;o%@8o6DVb-DIUOt;rA7Zqkdr_f#YackO{-WHbkhbz#xIZKXZvnvEm5 zqy=1*J0rIo$w#m!1hcO>t!)7E3@{KcA~AFJ1mfTv&z_QJ?G^KYLr)tTSp~V56pmai zijU>lBbsI)jXMU>N%|82%xnYVQR|G~sBqFV0d4O6tE9hS-})Wbk4UT*l<1YPa0dME z%4dp2&wEZnHs9=N?ya7z8ydklV$1s3jzCLe6r|b5_i)Oi)aKYqGeBI^ZuBez`a(2a-$50Ok=tVpxs0ZTk;p WW37K`!OrIZ0000C literal 0 HcmV?d00001 diff --git a/Resources/Textures/Decals/burnt.rsi/burnt2.png b/Resources/Textures/Decals/burnt.rsi/burnt2.png new file mode 100644 index 0000000000000000000000000000000000000000..01f8f220b2ddae1a13fac2b816531109a5b848d9 GIT binary patch literal 938 zcmV;b16BNqP)18A2vnpw(ar z1~qsht;3vCD6w`Ao}uGYnUsA1aPJrnOd)6t3!DMiI$6ER(;`s9#u7N6pd4cTwdf`G z2_S*!hJ`)wbZg_0F*v6MHg>;GCHx+Tzwt=JH}-T(U;23XN71bm6J#p9IFTkcm5gqK z^tAwduWz%!Cu7Bw`%{PCis#BPcvk^T9Mi6`N4!4&RvUe%3k*DgXzsb>EVX7P2z~>G z2Krrr1)9=8G5B6W`vj{g4YsN1zcPIW zV5X|>9a}N0^|cQ3pfrEhjEwHJG@W?V`+P6qA}w&JCyhP*2=lg}bc01jVF^I8;Vi)i z$25J`1XEDr2dgllPFL=UA+3cqy1hLF*B(=5xn)$H0500m$U z0e2oTkWELyx%aGmdnf@ivuFkGjjv`jofKps$SYI+o{QLmWYm8K086<%#GyXvdo6YO3$m!Aax?qf)&Kwi M07*qoM6N<$f@T`Jp8x;= literal 0 HcmV?d00001 diff --git a/Resources/Textures/Decals/burnt.rsi/burnt3.png b/Resources/Textures/Decals/burnt.rsi/burnt3.png new file mode 100644 index 0000000000000000000000000000000000000000..e9dcbe37533f6e1aa9f17dca58d5c2b15973408a GIT binary patch literal 928 zcmV;R17G}!P)a;W5Jit{9MAGY^Z#EoHA`ZHfq9@0+$c_ss#F3Yb>H5b2K)d9;0(;b2;6I(YfiwU zR-b2J0b1Sv3Va8?0W0tZ+=|v(^sm5|IuEc8z_0pnEn*Eg)rHngikQ=J>b^JNQUKjM z124sV@V=U@}kW6B%Z?YOXZZ67&`UX#a^V zgRKSR6c-ac9NCPJ)+sP}?|AZ=OUQfLXypjSnJtYb^FAr12DEu*x(wYpR<-;Fy!M$X z52e%uQ@veg?pTLhLe{bD$dvbOccIXcG>9sFVDbZAW`p^r92HlsY)$oI$1Dm>^mDco)UP^r= zL+Z-M(9I&I26LR!R#}p>toG$s2_8XIFDGbZO=)!|&3&SZk+GSTFg37rL_af6-vjic z595{^=*`gg1HNabOX;%Sr-W)pb9q;Pne_ox{7lkJJQ?RL?wAwc2x0GCII8SaXXUwA zh|&jo5Hh~96&b6gen5aShX_!KrDrZs^V{%1UMzI3){{b2u`{;`kj?~;+p#!H6W9Q($&N#+@YmG_~VwO}MVq9HEt4ibR! zhh*Y?R!gSl{1)dNci=DZ8~9Uv+L^73v7BmCYqohITkDjrUwzIW5+(lw{H*!6G_W@$ zHWYejpJ=k8`QHCOJc`y>tLoMXe;4Cdwq9TXUb2K5Mw&zu=pPS`GTPfadjU^`5@AN8LXHrEQ@sW!o?S0000>5u66hM z4m^NiHO3eX*Z_Or0K5TPU{`Y+mg`cwewV(X0aFctb1gUnw^Fnz1$haG6`-ls3TRhj zTWcO=&?oQ*m|9r)0Oqp#TJM`0+fp{iP&x4|kXCy(F~*WRg|4yHm7O$Z3@hZC3%Q7b1Bh-dPs1$Qf@v`@_y9w&{#5aS4fRjqi1w0A)j?W*E(IU2gdNo z9N$d7p$suMngBj(^BcWn-b(pC1mEZxK88gPUSprtVEGXMrT{QD;1|8_{{_AmfH!*V z9dig8R{->c-pl3Y{#o_0o=P(3&A0uY&rB&Y*RmE;*Pk8zpt(CK!dC-Q9t-uZ#*1$#Q# zs9XRl_pag=_br{6ZoGQw63>Rr!|sEk;zL-tKE)=HtaD)P_Uwv=$Pjo*@23L$0)Vhy z04mMrG43W-@<$#%bt*m^j@A9H?@Bob9$)( zcjIm5%Yuhml7uSvU*J%ik1Ql~q4#|OWM7xEbH9mg zc=V!P9)U|X7FkdrQz<{vf5mjU9`M~HvpasHv#E72-S5h)6L9_u9x#X3!t};m00000 LNkvXXu0mjfo00E? literal 0 HcmV?d00001 diff --git a/Resources/Textures/Decals/burnt.rsi/meta.json b/Resources/Textures/Decals/burnt.rsi/meta.json new file mode 100644 index 00000000000..48a8f33138c --- /dev/null +++ b/Resources/Textures/Decals/burnt.rsi/meta.json @@ -0,0 +1,27 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "From https://github.com/BeeStation/BeeStation-Hornet/blob/master/icons/turf/turf_damage.dmi at f2d6fbdf36aa0951049498cf28e028a38e32fe0b", + "states": [ + { + "name": "burnt1" + + }, + { + "name": "burnt2" + + }, + { + "name": "burnt3" + + }, + { + "name": "burnt4" + + } + ] +} From 0c5a053ae4ec06ad4471884dd81aa5053522d716 Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 19 Sep 2024 00:24:56 +0000 Subject: [PATCH 125/138] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 8190ecd8fe4..050ad0721c2 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: Aquif - changes: - - message: It is now possible to "lock" admin faxes such that they cannot be edited - by cybersun pens or any other IC means. - type: Add - id: 6895 - time: '2024-07-10T05:28:36.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/28972 - author: Ghagliiarghii changes: - message: The Librarian's Books Bag can now hold D&D related items such as dice @@ -3918,3 +3910,10 @@ id: 7394 time: '2024-09-18T23:55:26.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29998 +- author: Winkarst-cpu + changes: + - message: Now fire leaves burn marks on the tiles that were affected by it. + type: Add + id: 7395 + time: '2024-09-19T00:23:50.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/31939 From 1c3cfeeb35f425cd556103e4a673c01ae16cf69d Mon Sep 17 00:00:00 2001 From: ArchRBX <5040911+ArchRBX@users.noreply.github.com> Date: Thu, 19 Sep 2024 02:25:47 +0100 Subject: [PATCH 126/138] Coordinates under IFF Label on Mass Scanners and Shuttle Consoles (#31501) * adds coord label beneath iff label * fixed wrong coordinate system being used * changes the clamping on the label UI to instead normalise the UI's distance vector from the centre of the screen, fixes corner-hugging * cleaned up if-statement by moving the calc ahead of it * fixed clamping, fixed parenting issue, added draw cull on coord label --------- Co-authored-by: archrbx --- .../Shuttles/UI/ShuttleNavControl.xaml.cs | 47 +++++++++++++++---- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/Content.Client/Shuttles/UI/ShuttleNavControl.xaml.cs b/Content.Client/Shuttles/UI/ShuttleNavControl.xaml.cs index 64ead32586d..2674343e059 100644 --- a/Content.Client/Shuttles/UI/ShuttleNavControl.xaml.cs +++ b/Content.Client/Shuttles/UI/ShuttleNavControl.xaml.cs @@ -199,7 +199,9 @@ protected override void Draw(DrawingHandleScreen handle) var gridMatrix = _transform.GetWorldMatrix(gUid); var matty = Matrix3x2.Multiply(gridMatrix, ourWorldMatrixInvert); - var color = _shuttles.GetIFFColor(grid, self: false, iff); + + var labelColor = _shuttles.GetIFFColor(grid, self: false, iff); + var coordColor = new Color(labelColor.R * 0.8f, labelColor.G * 0.8f, labelColor.B * 0.8f, 0.5f); // Others default: // Color.FromHex("#FFC000FF") @@ -213,25 +215,52 @@ protected override void Draw(DrawingHandleScreen handle) var gridCentre = Vector2.Transform(gridBody.LocalCenter, matty); gridCentre.Y = -gridCentre.Y; + var distance = gridCentre.Length(); var labelText = Loc.GetString("shuttle-console-iff-label", ("name", labelName), ("distance", $"{distance:0.0}")); + var mapCoords = _transform.GetWorldPosition(gUid); + var coordsText = $"({mapCoords.X:0.0}, {mapCoords.Y:0.0})"; + // yes 1.0 scale is intended here. var labelDimensions = handle.GetDimensions(Font, labelText, 1f); + var coordsDimensions = handle.GetDimensions(Font, coordsText, 0.7f); // y-offset the control to always render below the grid (vertically) var yOffset = Math.Max(gridBounds.Height, gridBounds.Width) * MinimapScale / 1.8f; - // The actual position in the UI. We offset the matrix position to render it off by half its width - // plus by the offset. - var uiPosition = ScalePosition(gridCentre)- new Vector2(labelDimensions.X / 2f, -yOffset); + // The actual position in the UI. We centre the label by offsetting the matrix position + // by half the label's width, plus the y-offset + var gridScaledPosition = ScalePosition(gridCentre) - new Vector2(0, -yOffset); - // Look this is uggo so feel free to cleanup. We just need to clamp the UI position to within the viewport. - uiPosition = new Vector2(Math.Clamp(uiPosition.X, 0f, PixelWidth - labelDimensions.X ), - Math.Clamp(uiPosition.Y, 0f, PixelHeight - labelDimensions.Y)); + // Normalize the grid position if it exceeds the viewport bounds + // normalizing it instead of clamping it preserves the direction of the vector and prevents corner-hugging + var gridOffset = gridScaledPosition / PixelSize - new Vector2(0.5f, 0.5f); + var offsetMax = Math.Max(Math.Abs(gridOffset.X), Math.Abs(gridOffset.Y)) * 2f; + if (offsetMax > 1) + { + gridOffset = new Vector2(gridOffset.X / offsetMax, gridOffset.Y / offsetMax); + + gridScaledPosition = (gridOffset + new Vector2(0.5f, 0.5f)) * PixelSize; + } - handle.DrawString(Font, uiPosition, labelText, color); + var labelUiPosition = gridScaledPosition - new Vector2(labelDimensions.X / 2f, 0); + var coordUiPosition = gridScaledPosition - new Vector2(coordsDimensions.X / 2f, -labelDimensions.Y); + + // clamp the IFF label's UI position to within the viewport extents so it hugs the edges of the viewport + // coord label intentionally isn't clamped so we don't get ugly clutter at the edges + var controlExtents = PixelSize - new Vector2(labelDimensions.X, labelDimensions.Y); //new Vector2(labelDimensions.X * 2f, labelDimensions.Y); + labelUiPosition = Vector2.Clamp(labelUiPosition, Vector2.Zero, controlExtents); + + // draw IFF label + handle.DrawString(Font, labelUiPosition, labelText, labelColor); + + // only draw coords label if close enough + if (offsetMax < 1) + { + handle.DrawString(Font, coordUiPosition, coordsText, 0.7f, coordColor); + } } // Detailed view @@ -241,7 +270,7 @@ protected override void Draw(DrawingHandleScreen handle) if (!gridAABB.Intersects(viewAABB)) continue; - DrawGrid(handle, matty, grid, color); + DrawGrid(handle, matty, grid, labelColor); DrawDocks(handle, gUid, matty); } } From c2f0626e029c1f3b33aa9b7770ef7d3ee0fa2aae Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 19 Sep 2024 01:26:53 +0000 Subject: [PATCH 127/138] Automatic changelog update --- Resources/Changelog/Changelog.yml | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 050ad0721c2..4b779d845b6 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: Ghagliiarghii - changes: - - message: The Librarian's Books Bag can now hold D&D related items such as dice - and battlemats. - type: Tweak - id: 6896 - time: '2024-07-10T05:51:01.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29863 - author: Beck Thompson, Tayrtahn changes: - message: Typing indicators now correctly stack and will not overwrite your default @@ -3917,3 +3909,14 @@ id: 7395 time: '2024-09-19T00:23:50.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/31939 +- author: ArchRBX + changes: + - message: Mass scanners and shuttle consoles now display coordinates beneath IFF + labels + type: Add + - message: IFF labels that are beyond the viewport extents maintain their heading + and don't hug corners + type: Fix + id: 7396 + time: '2024-09-19T01:25:47.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/31501 From 9c905cd58f5453c6ab7821709bdbf5fcf1249df9 Mon Sep 17 00:00:00 2001 From: Luiz Costa <33888056+luizwritescode@users.noreply.github.com> Date: Wed, 18 Sep 2024 23:15:44 -0300 Subject: [PATCH 128/138] Fix TEG acting as infinite energy source on destruction (#29972) * TEG now checks for power supply before checking for IsFullyBuilt * Update Content.Server/Power/Generation/Teg/TegSystem.cs Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> --------- Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> --- Content.Server/Power/Generation/Teg/TegSystem.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Content.Server/Power/Generation/Teg/TegSystem.cs b/Content.Server/Power/Generation/Teg/TegSystem.cs index 9fb7d5ff1f6..027f2570402 100644 --- a/Content.Server/Power/Generation/Teg/TegSystem.cs +++ b/Content.Server/Power/Generation/Teg/TegSystem.cs @@ -102,10 +102,6 @@ private void GeneratorExamined(EntityUid uid, TegGeneratorComponent component, E private void GeneratorUpdate(EntityUid uid, TegGeneratorComponent component, ref AtmosDeviceUpdateEvent args) { - var tegGroup = GetNodeGroup(uid); - if (tegGroup is not { IsFullyBuilt: true }) - return; - var supplier = Comp(uid); var powerReceiver = Comp(uid); if (!powerReceiver.Powered) @@ -114,6 +110,10 @@ private void GeneratorUpdate(EntityUid uid, TegGeneratorComponent component, ref return; } + var tegGroup = GetNodeGroup(uid); + if (tegGroup is not { IsFullyBuilt: true }) + return; + var circA = tegGroup.CirculatorA!.Owner; var circB = tegGroup.CirculatorB!.Owner; From b1296294052e6bb1af45efb97c350cc898746b22 Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 19 Sep 2024 02:16:50 +0000 Subject: [PATCH 129/138] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 4b779d845b6..8eba2ed6d88 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: Beck Thompson, Tayrtahn - changes: - - message: Typing indicators now correctly stack and will not overwrite your default - species indicator. - type: Fix - id: 6897 - time: '2024-07-10T05:51:48.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29492 - author: Winkarst-cpu changes: - message: Now confirmation popup is displayed and item panel status is updated @@ -3920,3 +3912,10 @@ id: 7396 time: '2024-09-19T01:25:47.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/31501 +- author: coffeeware + changes: + - message: a powered TEG won't produce infinite power when destroyed + type: Fix + id: 7397 + time: '2024-09-19T02:15:44.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29972 From 550c4231816cd28251d3c42d32002bcf0ac4d5aa Mon Sep 17 00:00:00 2001 From: IProduceWidgets <107586145+IProduceWidgets@users.noreply.github.com> Date: Wed, 18 Sep 2024 22:17:13 -0400 Subject: [PATCH 130/138] Clean up solution regen and drain comps (#29777) * clean up solution regen and drain comps * Tape applied. * Update Content.Server/Chemistry/Components/SolutionRegenerationComponent.cs Co-authored-by: Tayrtahn * remain entity * That has to be a rogue test fail. --------- Co-authored-by: Tayrtahn --- .../SolutionRegenerationComponent.cs | 12 +++++----- .../SolutionRegenerationSystem.cs | 4 ++-- .../Fluids/Components/DrainComponent.cs | 24 +++++++++---------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Content.Server/Chemistry/Components/SolutionRegenerationComponent.cs b/Content.Server/Chemistry/Components/SolutionRegenerationComponent.cs index 23bf6b21573..03c0ffe0c1a 100644 --- a/Content.Server/Chemistry/Components/SolutionRegenerationComponent.cs +++ b/Content.Server/Chemistry/Components/SolutionRegenerationComponent.cs @@ -14,31 +14,31 @@ public sealed partial class SolutionRegenerationComponent : Component /// /// The name of the solution to add to. /// - [DataField("solution", required: true), ViewVariables(VVAccess.ReadWrite)] + [DataField("solution", required: true)] public string SolutionName = string.Empty; /// /// The solution to add reagents to. /// - [DataField("solutionRef")] - public Entity? Solution = null; + [DataField] + public Entity? SolutionRef = null; /// /// The reagent(s) to be regenerated in the solution. /// - [DataField("generated", required: true), ViewVariables(VVAccess.ReadWrite)] + [DataField(required: true)] public Solution Generated = default!; /// /// How long it takes to regenerate once. /// - [DataField("duration"), ViewVariables(VVAccess.ReadWrite)] + [DataField] public TimeSpan Duration = TimeSpan.FromSeconds(1); /// /// The time when the next regeneration will occur. /// - [DataField("nextChargeTime", customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)] + [DataField("nextChargeTime", customTypeSerializer: typeof(TimeOffsetSerializer))] [AutoPausedField] public TimeSpan NextRegenTime = TimeSpan.FromSeconds(0); } diff --git a/Content.Server/Chemistry/EntitySystems/SolutionRegenerationSystem.cs b/Content.Server/Chemistry/EntitySystems/SolutionRegenerationSystem.cs index 6a600628572..bccd5947069 100644 --- a/Content.Server/Chemistry/EntitySystems/SolutionRegenerationSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/SolutionRegenerationSystem.cs @@ -24,7 +24,7 @@ public override void Update(float frameTime) // timer ignores if its full, it's just a fixed cycle regen.NextRegenTime = _timing.CurTime + regen.Duration; - if (_solutionContainer.ResolveSolution((uid, manager), regen.SolutionName, ref regen.Solution, out var solution)) + if (_solutionContainer.ResolveSolution((uid, manager), regen.SolutionName, ref regen.SolutionRef, out var solution)) { var amount = FixedPoint2.Min(solution.AvailableVolume, regen.Generated.Volume); if (amount <= FixedPoint2.Zero) @@ -41,7 +41,7 @@ public override void Update(float frameTime) generated = regen.Generated.Clone().SplitSolution(amount); } - _solutionContainer.TryAddSolution(regen.Solution.Value, generated); + _solutionContainer.TryAddSolution(regen.SolutionRef.Value, generated); } } } diff --git a/Content.Shared/Fluids/Components/DrainComponent.cs b/Content.Shared/Fluids/Components/DrainComponent.cs index 4fb4fe94383..50cb5f51958 100644 --- a/Content.Shared/Fluids/Components/DrainComponent.cs +++ b/Content.Shared/Fluids/Components/DrainComponent.cs @@ -23,14 +23,14 @@ public sealed partial class DrainComponent : Component [DataField] public Entity? Solution = null; - [DataField("accumulator")] + [DataField] public float Accumulator = 0f; /// /// Does this drain automatically absorb surrouding puddles? Or is it a drain designed to empty - /// solutions in it manually? + /// solutions in it manually? /// - [DataField("autoDrain"), ViewVariables(VVAccess.ReadOnly)] + [DataField] public bool AutoDrain = true; /// @@ -38,47 +38,47 @@ public sealed partial class DrainComponent : Component /// Divided by puddles, so if there are 5 puddles this will take 1/5 from each puddle. /// This will stay fixed to 1 second no matter what DrainFrequency is. /// - [DataField("unitsPerSecond")] + [DataField] public float UnitsPerSecond = 6f; /// /// How many units are ejected from the buffer per second. /// - [DataField("unitsDestroyedPerSecond")] + [DataField] public float UnitsDestroyedPerSecond = 3f; /// /// How many (unobstructed) tiles away the drain will /// drain puddles from. /// - [DataField("range"), ViewVariables(VVAccess.ReadWrite)] + [DataField] public float Range = 2f; /// /// How often in seconds the drain checks for puddles around it. /// If the EntityQuery seems a bit unperformant this can be increased. /// - [DataField("drainFrequency")] + [DataField] public float DrainFrequency = 1f; /// /// How much time it takes to unclog it with a plunger /// - [DataField("unclogDuration"), ViewVariables(VVAccess.ReadWrite)] + [DataField] public float UnclogDuration = 1f; /// /// What's the probability of uncloging on each try /// - [DataField("unclogProbability"), ViewVariables(VVAccess.ReadWrite)] + [DataField] public float UnclogProbability = 0.75f; - [DataField("manualDrainSound"), ViewVariables(VVAccess.ReadOnly)] + [DataField] public SoundSpecifier ManualDrainSound = new SoundPathSpecifier("/Audio/Effects/Fluids/slosh.ogg"); - [DataField("plungerSound"), ViewVariables(VVAccess.ReadOnly)] + [DataField] public SoundSpecifier PlungerSound = new SoundPathSpecifier("/Audio/Items/Janitor/plunger.ogg"); - [DataField("unclogSound"), ViewVariables(VVAccess.ReadOnly)] + [DataField] public SoundSpecifier UnclogSound = new SoundPathSpecifier("/Audio/Effects/Fluids/glug.ogg"); } From bdd0561254a0f2b6cef0a032af566bd908e9de58 Mon Sep 17 00:00:00 2001 From: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com> Date: Thu, 19 Sep 2024 14:21:26 +1200 Subject: [PATCH 131/138] Make status effect networking not use `TryAddStatusEffect` (#28766) * Make status effect networking not use `TryAddStatusEffect` * a --- .../StatusEffect/StatusEffectsSystem.cs | 74 ++++++++++--------- 1 file changed, 39 insertions(+), 35 deletions(-) diff --git a/Content.Shared/StatusEffect/StatusEffectsSystem.cs b/Content.Shared/StatusEffect/StatusEffectsSystem.cs index 9806077f9bb..95abea63db0 100644 --- a/Content.Shared/StatusEffect/StatusEffectsSystem.cs +++ b/Content.Shared/StatusEffect/StatusEffectsSystem.cs @@ -14,6 +14,7 @@ public sealed class StatusEffectsSystem : EntitySystem [Dependency] private readonly IComponentFactory _componentFactory = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly AlertsSystem _alertsSystem = default!; + private List _toRemove = new(); public override void Initialize() { @@ -32,18 +33,28 @@ public override void Update(float frameTime) var curTime = _gameTiming.CurTime; var enumerator = EntityQueryEnumerator(); + _toRemove.Clear(); while (enumerator.MoveNext(out var uid, out _, out var status)) { - foreach (var state in status.ActiveEffects.ToArray()) + if (status.ActiveEffects.Count == 0) + { + // This shouldn't happen, but just in case something sneaks through + _toRemove.Add(uid); + continue; + } + + foreach (var state in status.ActiveEffects) { - // if we're past the end point of the effect if (curTime > state.Value.Cooldown.Item2) - { TryRemoveStatusEffect(uid, state.Key, status); - } } } + + foreach (var uid in _toRemove) + { + RemComp(uid); + } } private void OnGetState(EntityUid uid, StatusEffectsComponent component, ref ComponentGetState args) @@ -62,29 +73,21 @@ private void OnHandleState(EntityUid uid, StatusEffectsComponent component, ref component.AllowedEffects.AddRange(state.AllowedEffects); // Remove non-existent effects. - foreach (var effect in component.ActiveEffects.Keys) + foreach (var key in component.ActiveEffects.Keys) { - if (!state.ActiveEffects.ContainsKey(effect)) - { - TryRemoveStatusEffect(uid, effect, component, remComp: false); - } + if (!state.ActiveEffects.ContainsKey(key)) + component.ActiveEffects.Remove(key); } foreach (var (key, effect) in state.ActiveEffects) { - // don't bother with anything if we already have it - if (component.ActiveEffects.ContainsKey(key)) - { - component.ActiveEffects[key] = new(effect); - continue; - } - - var time = effect.Cooldown.Item2 - effect.Cooldown.Item1; - - TryAddStatusEffect(uid, key, time, true, component, effect.Cooldown.Item1); - component.ActiveEffects[key].RelevantComponent = effect.RelevantComponent; - // state handling should not add networked components, that is handled separately by the client game state manager. + component.ActiveEffects[key] = new(effect); } + + if (component.ActiveEffects.Count == 0) + RemComp(uid); + else + EnsureComp(uid); } private void OnRejuvenate(EntityUid uid, StatusEffectsComponent component, RejuvenateEvent args) @@ -109,18 +112,16 @@ public bool TryAddStatusEffect(EntityUid uid, string key, TimeSpan time, bool if (!Resolve(uid, ref status, false)) return false; - if (TryAddStatusEffect(uid, key, time, refresh, status)) - { - // If they already have the comp, we just won't bother updating anything. - if (!EntityManager.HasComponent(uid)) - { - var comp = EntityManager.AddComponent(uid); - status.ActiveEffects[key].RelevantComponent = _componentFactory.GetComponentName(comp.GetType()); - } + if (!TryAddStatusEffect(uid, key, time, refresh, status)) + return false; + + if (HasComp(uid)) return true; - } - return false; + EntityManager.AddComponent(uid); + status.ActiveEffects[key].RelevantComponent = _componentFactory.GetComponentName(); + return true; + } public bool TryAddStatusEffect(EntityUid uid, string key, TimeSpan time, bool refresh, string component, @@ -162,8 +163,12 @@ public bool TryAddStatusEffect(EntityUid uid, string key, TimeSpan time, bool re /// If the effect already exists, it will simply replace the cooldown with the new one given. /// If you want special 'effect merging' behavior, do it your own damn self! /// - public bool TryAddStatusEffect(EntityUid uid, string key, TimeSpan time, bool refresh, - StatusEffectsComponent? status = null, TimeSpan? startTime = null) + public bool TryAddStatusEffect(EntityUid uid, + string key, + TimeSpan time, + bool refresh, + StatusEffectsComponent? status = null, + TimeSpan? startTime = null) { if (!Resolve(uid, ref status, false)) return false; @@ -334,8 +339,7 @@ public bool HasStatusEffect(EntityUid uid, string key, /// The entity to check on. /// The status effect ID to check for /// The status effect component, should you already have it. - public bool CanApplyEffect(EntityUid uid, string key, - StatusEffectsComponent? status = null) + public bool CanApplyEffect(EntityUid uid, string key, StatusEffectsComponent? status = null) { // don't log since stuff calling this prolly doesn't care if we don't actually have it if (!Resolve(uid, ref status, false)) From 828688bd58a3cb56f1af1bc795f96af6e4001af8 Mon Sep 17 00:00:00 2001 From: Morb0 <14136326+Morb0@users.noreply.github.com> Date: Thu, 19 Sep 2024 10:33:03 +0300 Subject: [PATCH 132/138] Update publish publish --- .github/workflows/publish-publish.yml | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/.github/workflows/publish-publish.yml b/.github/workflows/publish-publish.yml index 4ba26382c53..6729f278a18 100644 --- a/.github/workflows/publish-publish.yml +++ b/.github/workflows/publish-publish.yml @@ -1,7 +1,7 @@ name: Publish Public -#concurrency: -# group: publish +concurrency: + group: publish on: workflow_dispatch: @@ -19,6 +19,7 @@ jobs: - uses: actions/checkout@v3.6.0 with: submodules: 'recursive' + - name: Setup .NET Core uses: actions/setup-dotnet@v3.2.0 with: @@ -41,21 +42,10 @@ jobs: - name: Package client run: dotnet run --project Content.Packaging client --no-wipe-release - - name: Upload build artifact - id: artifact-upload-step - uses: actions/upload-artifact@v4 - with: - name: build - path: release/*.zip - compression-level: 0 - retention-days: 0 - - name: Publish version - run: Tools/publish_github_artifact.py + run: Tools/publish_multi_request.py env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN_PUBLIC }} - ARTIFACT_ID: ${{ steps.artifact-upload-step.outputs.artifact-id }} GITHUB_REPOSITORY: ${{ vars.GITHUB_REPOSITORY }} FORK_ID: ${{ vars.FORK_ID_PUBLIC }} @@ -69,8 +59,3 @@ jobs: # run: Tools/actions_changelog_rss.py # env: # CHANGELOG_RSS_KEY: ${{ secrets.CHANGELOG_RSS_KEY }} - - - uses: geekyeggo/delete-artifact@v5 - if: always() - with: - name: build From 3fc9f96b75b2a3ebc1a02319758eb6853452cb05 Mon Sep 17 00:00:00 2001 From: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> Date: Thu, 19 Sep 2024 00:42:49 -0700 Subject: [PATCH 133/138] Move PlaceableSurfaceComponent usages to PlaceableSurfaceSystem (#28384) * Move placeable check to PlaceableSurfaceSystem This check stops entities from being inserted into a storage entity when it has a PlaceableSurfaceComponent. The entity is instead placed on top of the entity like a table. * Move SetPlaceable to PlaceableSurfaceSystem * Update to transform system and consolidate code * Fix interaction with storage that has a placeable component * deadlock --------- Co-authored-by: metalgearsloth --- .../Placeable/PlaceableSurfaceSystem.cs | 29 ++++++++++++++++--- .../SharedEntityStorageSystem.cs | 3 -- .../EntitySystems/SharedStorageSystem.cs | 4 ++- Content.Shared/Storage/StorageComponent.cs | 3 ++ 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/Content.Shared/Placeable/PlaceableSurfaceSystem.cs b/Content.Shared/Placeable/PlaceableSurfaceSystem.cs index a9a9390a6e0..c332064ea38 100644 --- a/Content.Shared/Placeable/PlaceableSurfaceSystem.cs +++ b/Content.Shared/Placeable/PlaceableSurfaceSystem.cs @@ -1,6 +1,7 @@ using System.Numerics; using Content.Shared.Hands.EntitySystems; using Content.Shared.Interaction; +using Content.Shared.Storage; using Content.Shared.Storage.Components; namespace Content.Shared.Placeable; @@ -8,12 +9,16 @@ namespace Content.Shared.Placeable; public sealed class PlaceableSurfaceSystem : EntitySystem { [Dependency] private readonly SharedHandsSystem _handsSystem = default!; + [Dependency] private readonly SharedTransformSystem _transformSystem = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnAfterInteractUsing); + SubscribeLocalEvent(OnStorageInteractUsingAttempt); + SubscribeLocalEvent(OnStorageAfterOpen); + SubscribeLocalEvent(OnStorageAfterClose); } public void SetPlaceable(EntityUid uid, bool isPlaceable, PlaceableSurfaceComponent? surface = null) @@ -21,6 +26,9 @@ public void SetPlaceable(EntityUid uid, bool isPlaceable, PlaceableSurfaceCompon if (!Resolve(uid, ref surface, false)) return; + if (surface.IsPlaceable == isPlaceable) + return; + surface.IsPlaceable = isPlaceable; Dirty(uid, surface); } @@ -59,11 +67,24 @@ private void OnAfterInteractUsing(EntityUid uid, PlaceableSurfaceComponent surfa if (!_handsSystem.TryDrop(args.User, args.Used)) return; - if (surface.PlaceCentered) - Transform(args.Used).LocalPosition = Transform(uid).LocalPosition + surface.PositionOffset; - else - Transform(args.Used).Coordinates = args.ClickLocation; + _transformSystem.SetCoordinates(args.Used, + surface.PlaceCentered ? Transform(uid).Coordinates.Offset(surface.PositionOffset) : args.ClickLocation); args.Handled = true; } + + private void OnStorageInteractUsingAttempt(Entity ent, ref StorageInteractUsingAttemptEvent args) + { + args.Cancelled = true; + } + + private void OnStorageAfterOpen(Entity ent, ref StorageAfterOpenEvent args) + { + SetPlaceable(ent.Owner, true, ent.Comp); + } + + private void OnStorageAfterClose(Entity ent, ref StorageAfterCloseEvent args) + { + SetPlaceable(ent.Owner, false, ent.Comp); + } } diff --git a/Content.Shared/Storage/EntitySystems/SharedEntityStorageSystem.cs b/Content.Shared/Storage/EntitySystems/SharedEntityStorageSystem.cs index 4932613d0e6..309ac0a2e09 100644 --- a/Content.Shared/Storage/EntitySystems/SharedEntityStorageSystem.cs +++ b/Content.Shared/Storage/EntitySystems/SharedEntityStorageSystem.cs @@ -487,9 +487,6 @@ private void ModifyComponents(EntityUid uid, SharedEntityStorageComponent? compo } } - if (TryComp(uid, out var surface)) - _placeableSurface.SetPlaceable(uid, component.Open, surface); - _appearance.SetData(uid, StorageVisuals.Open, component.Open); _appearance.SetData(uid, StorageVisuals.HasContents, component.Contents.ContainedEntities.Count > 0); } diff --git a/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs b/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs index def9d797c48..d6fde292a14 100644 --- a/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs +++ b/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs @@ -364,7 +364,9 @@ private void OnInteractUsing(EntityUid uid, StorageComponent storageComp, Intera if (args.Handled || !CanInteract(args.User, (uid, storageComp), storageComp.ClickInsert, false)) return; - if (HasComp(uid)) + var attemptEv = new StorageInteractUsingAttemptEvent(); + RaiseLocalEvent(uid, ref attemptEv); + if (attemptEv.Cancelled) return; PlayerInsertHeldEntity((uid, storageComp), args.User); diff --git a/Content.Shared/Storage/StorageComponent.cs b/Content.Shared/Storage/StorageComponent.cs index a666169f529..d2c607e57f7 100644 --- a/Content.Shared/Storage/StorageComponent.cs +++ b/Content.Shared/Storage/StorageComponent.cs @@ -238,6 +238,9 @@ public AnimateInsertingEntitiesEvent(NetEntity storage, List storedEn [ByRefEvent] public record struct StorageInteractAttemptEvent(bool Silent, bool Cancelled = false); + [ByRefEvent] + public record struct StorageInteractUsingAttemptEvent(bool Cancelled = false); + [NetSerializable] [Serializable] public enum StorageVisuals : byte From 3acf6b93a109ea542b3110c1f9b7fc59c6976aa3 Mon Sep 17 00:00:00 2001 From: Willhelm53 <97707302+Willhelm53@users.noreply.github.com> Date: Thu, 19 Sep 2024 03:51:33 -0400 Subject: [PATCH 134/138] Padded ItemStatus Text (#29560) * Back in the saddle again! <(8o) * if you like my STYLE you should see my SHEETS ;-) * stylesheet change works for ItemStatusNotHeld but broken for ItemStatus. Just using xaml for now. * teehee * beeg --------- Co-authored-by: metalgearsloth --- Content.Client/Stylesheets/StyleNano.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Content.Client/Stylesheets/StyleNano.cs b/Content.Client/Stylesheets/StyleNano.cs index 0bd75003a20..ccd36c35e82 100644 --- a/Content.Client/Stylesheets/StyleNano.cs +++ b/Content.Client/Stylesheets/StyleNano.cs @@ -695,6 +695,18 @@ public StyleNano(IResourceCache resCache) : base(resCache) new StyleProperty("font-color", Color.FromHex("#E5E5E581")), }), + // ItemStatus for hands + Element() + .Class(StyleClassItemStatusNotHeld) + .Prop("font", notoSansItalic10) + .Prop("font-color", ItemStatusNotHeldColor) + .Prop(nameof(Control.Margin), new Thickness(4, 0, 0, 2)), + + Element() + .Class(StyleClassItemStatus) + .Prop(nameof(RichTextLabel.LineHeightScale), 0.7f) + .Prop(nameof(Control.Margin), new Thickness(4, 0, 0, 2)), + // Context Menu window Element().Class(ContextMenuPopup.StyleClassContextMenuPopup) .Prop(PanelContainer.StylePropertyPanel, contextMenuBackground), From 94ad76fd07f148628c1b5d8070565635957caeb2 Mon Sep 17 00:00:00 2001 From: Tayrtahn Date: Thu, 19 Sep 2024 04:02:37 -0400 Subject: [PATCH 135/138] Fix Set Outfit command/verb (#29672) * Filter Set Outfit menu to exclude loadout sets * Apply loadouts to job outfits * Use appropriate species for Urists * squishy --------- Co-authored-by: metalgearsloth --- .../UI/SetOutfit/SetOutfitMenu.xaml.cs | 18 +++++++--- .../Commands/SetOutfitCommand.cs | 36 +++++++++++++++++++ 2 files changed, 49 insertions(+), 5 deletions(-) diff --git a/Content.Client/Administration/UI/SetOutfit/SetOutfitMenu.xaml.cs b/Content.Client/Administration/UI/SetOutfit/SetOutfitMenu.xaml.cs index 7cb32b43df5..615f1434df2 100644 --- a/Content.Client/Administration/UI/SetOutfit/SetOutfitMenu.xaml.cs +++ b/Content.Client/Administration/UI/SetOutfit/SetOutfitMenu.xaml.cs @@ -1,14 +1,13 @@ +using System.Linq; using System.Numerics; using Content.Client.UserInterface.Controls; +using Content.Shared.Preferences.Loadouts; using Content.Shared.Roles; using Robust.Client.AutoGenerated; using Robust.Client.Console; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; using Robust.Client.UserInterface.XAML; -using Robust.Shared.GameObjects; -using Robust.Shared.IoC; -using Robust.Shared.Localization; using Robust.Shared.Prototypes; namespace Content.Client.Administration.UI.SetOutfit @@ -65,9 +64,18 @@ private void SearchBarOnOnTextChanged(LineEdit.LineEditEventArgs obj) PopulateByFilter(SearchBar.Text); } + private IEnumerable GetPrototypes() + { + // Filter out any StartingGearPrototypes that belong to loadouts + var loadouts = _prototypeManager.EnumeratePrototypes(); + var loadoutGears = loadouts.Select(l => l.StartingGear); + return _prototypeManager.EnumeratePrototypes() + .Where(p => !loadoutGears.Contains(p.ID)); + } + private void PopulateList() { - foreach (var gear in _prototypeManager.EnumeratePrototypes()) + foreach (var gear in GetPrototypes()) { OutfitList.Add(GetItem(gear, OutfitList)); } @@ -76,7 +84,7 @@ private void PopulateList() private void PopulateByFilter(string filter) { OutfitList.Clear(); - foreach (var gear in _prototypeManager.EnumeratePrototypes()) + foreach (var gear in GetPrototypes()) { if (!string.IsNullOrEmpty(filter) && gear.ID.ToLowerInvariant().Contains(filter.Trim().ToLowerInvariant())) diff --git a/Content.Server/Administration/Commands/SetOutfitCommand.cs b/Content.Server/Administration/Commands/SetOutfitCommand.cs index ff4d34705a6..9240e7b91b6 100644 --- a/Content.Server/Administration/Commands/SetOutfitCommand.cs +++ b/Content.Server/Administration/Commands/SetOutfitCommand.cs @@ -4,11 +4,15 @@ using Content.Server.Preferences.Managers; using Content.Shared.Access.Components; using Content.Shared.Administration; +using Content.Shared.Clothing; using Content.Shared.Hands.Components; +using Content.Shared.Humanoid; using Content.Shared.Inventory; using Content.Shared.PDA; using Content.Shared.Preferences; +using Content.Shared.Preferences.Loadouts; using Content.Shared.Roles; +using Content.Shared.Station; using Robust.Shared.Console; using Robust.Shared.Player; using Robust.Shared.Prototypes; @@ -82,9 +86,11 @@ public static bool SetOutfit(EntityUid target, string gear, IEntityManager entit return false; HumanoidCharacterProfile? profile = null; + ICommonSession? session = null; // Check if we are setting the outfit of a player to respect the preferences if (entityManager.TryGetComponent(target, out ActorComponent? actorComponent)) { + session = actorComponent.PlayerSession; var userId = actorComponent.PlayerSession.UserId; var preferencesManager = IoCManager.Resolve(); var prefs = preferencesManager.GetPreferences(userId); @@ -128,6 +134,36 @@ public static bool SetOutfit(EntityUid target, string gear, IEntityManager entit } } + // See if this starting gear is associated with a job + var jobs = prototypeManager.EnumeratePrototypes(); + foreach (var job in jobs) + { + if (job.StartingGear != gear) + continue; + + var jobProtoId = LoadoutSystem.GetJobPrototype(job.ID); + if (!prototypeManager.TryIndex(jobProtoId, out var jobProto)) + break; + + // Don't require a player, so this works on Urists + profile ??= entityManager.TryGetComponent(target, out var comp) + ? HumanoidCharacterProfile.DefaultWithSpecies(comp.Species) + : new HumanoidCharacterProfile(); + // Try to get the user's existing loadout for the role + profile.Loadouts.TryGetValue(jobProtoId, out var roleLoadout); + + if (roleLoadout == null) + { + // If they don't have a loadout for the role, make a default one + roleLoadout = new RoleLoadout(jobProtoId); + roleLoadout.SetDefault(profile, session, prototypeManager); + } + + // Equip the target with the job loadout + var stationSpawning = entityManager.System(); + stationSpawning.EquipRoleLoadout(target, roleLoadout, jobProto); + } + return true; } } From 700df19e9b7a663c472db6c41736d05cd985087c Mon Sep 17 00:00:00 2001 From: Morb0 <14136326+Morb0@users.noreply.github.com> Date: Thu, 19 Sep 2024 11:04:59 +0300 Subject: [PATCH 136/138] Update locale --- .../ss14-ru/prototypes/actions/anomaly.ftl | 2 + .../entities/clothing/eyes/glasses.ftl | 2 +- .../entities/clothing/head/hoods.ftl | 2 + .../entities/markers/spawners/mobs.ftl | 3 + .../markers/spawners/random/anomaly.ftl | 2 + .../prototypes/entities/mobs/npcs/pets.ftl | 2 + .../objects/consumable/food/produce.ftl | 10 ++++ .../objects/devices/encryption_keys.ftl | 2 + .../objects/devices/station_beacon.ftl | 3 + .../entities/objects/fun/immovable_rod.ftl | 2 + .../prototypes/entities/objects/fun/toys.ftl | 2 + .../objects/specific/hydroponics/seeds.ftl | 8 +++ .../structures/doors/airlocks/access.ftl | 3 + .../structures/machines/vending_machines.ftl | 2 + .../specific/anomaly/anomaly_injections.ftl | 22 +++++++ .../specific/anomaly/anomaly_injectors.ftl | 32 ++++++++++ .../structures/wallmounts/intercom.ftl | 2 + .../ss14-ru/prototypes/gamerules/events.ftl | 2 + Resources/Locale/ru-RU/accent/accents.ftl | 6 ++ Resources/Locale/ru-RU/accent/skeleton.ftl | 24 ++++++++ .../Locale/ru-RU/actions/ui/actionslot.ftl | 1 + .../advertisements/vending/bruiseomat.ftl | 43 +++++++++++++ .../Locale/ru-RU/anomaly/inner_anomaly.ftl | 15 +++++ .../communications-console-component.ftl | 1 + .../Locale/ru-RU/flavors/flavor-profiles.ftl | 3 + .../ghost/roles/ghost-role-component.ftl | 2 + Resources/Locale/ru-RU/guardian/guardian.ftl | 1 + Resources/Locale/ru-RU/markings/gauze.ftl | 2 + Resources/Locale/ru-RU/mech/mech.ftl | 1 + .../ru-RU/mind/commands/rename-command.ftl | 5 ++ .../ru-RU/navmap-beacons/station-beacons.ftl | 1 + .../nutrition/components/food-sequence.ftl | 5 ++ .../conditions/steal-target-groups.ftl | 60 +++++++++++++++++++ .../ru-RU/preferences/loadout-groups.ftl | 1 + Resources/Locale/ru-RU/replays/replays.ftl | 1 + .../ru-RU/round-end/round-end-system.ftl | 1 + Resources/Locale/ru-RU/seeds/seeds.ftl | 8 +++ Resources/Locale/ru-RU/shuttles/emergency.ftl | 4 +- .../ss14-ru/prototypes/actions/anomaly.ftl | 2 + .../entities/clothing/head/hoods.ftl | 2 + .../entities/markers/spawners/mobs.ftl | 3 + .../markers/spawners/random/anomaly.ftl | 2 + .../prototypes/entities/mobs/npcs/pets.ftl | 2 + .../objects/consumable/food/produce.ftl | 10 ++++ .../objects/devices/encryption_keys.ftl | 2 + .../objects/devices/station_beacon.ftl | 3 + .../entities/objects/fun/immovable_rod.ftl | 2 + .../prototypes/entities/objects/fun/toys.ftl | 2 + .../objects/specific/hydroponics/seeds.ftl | 8 +++ .../structures/doors/airlocks/access.ftl | 3 + .../structures/machines/vending_machines.ftl | 2 + .../specific/anomaly/anomaly_injections.ftl | 22 +++++++ .../specific/anomaly/anomaly_injectors.ftl | 32 ++++++++++ .../structures/wallmounts/intercom.ftl | 2 + .../ss14-ru/prototypes/gamerules/events.ftl | 2 + .../ru-RU/station-events/events/ion-storm.ftl | 1 + Resources/Locale/ru-RU/traits/traits.ftl | 4 ++ .../wires/components/wires-component.ftl | 6 ++ 58 files changed, 397 insertions(+), 3 deletions(-) create mode 100644 Resources/Locale/en-US/ss14-ru/prototypes/actions/anomaly.ftl create mode 100644 Resources/Locale/en-US/ss14-ru/prototypes/entities/structures/specific/anomaly/anomaly_injections.ftl create mode 100644 Resources/Locale/en-US/ss14-ru/prototypes/entities/structures/specific/anomaly/anomaly_injectors.ftl create mode 100644 Resources/Locale/ru-RU/accent/skeleton.ftl create mode 100644 Resources/Locale/ru-RU/advertisements/vending/bruiseomat.ftl create mode 100644 Resources/Locale/ru-RU/anomaly/inner_anomaly.ftl create mode 100644 Resources/Locale/ru-RU/mind/commands/rename-command.ftl create mode 100644 Resources/Locale/ru-RU/objectives/conditions/steal-target-groups.ftl create mode 100644 Resources/Locale/ru-RU/ss14-ru/prototypes/actions/anomaly.ftl create mode 100644 Resources/Locale/ru-RU/ss14-ru/prototypes/entities/structures/specific/anomaly/anomaly_injections.ftl create mode 100644 Resources/Locale/ru-RU/ss14-ru/prototypes/entities/structures/specific/anomaly/anomaly_injectors.ftl diff --git a/Resources/Locale/en-US/ss14-ru/prototypes/actions/anomaly.ftl b/Resources/Locale/en-US/ss14-ru/prototypes/actions/anomaly.ftl new file mode 100644 index 00000000000..2bfb1895263 --- /dev/null +++ b/Resources/Locale/en-US/ss14-ru/prototypes/actions/anomaly.ftl @@ -0,0 +1,2 @@ +ent-ActionAnomalyPulse = Anomaly pulse + .desc = Release a pulse of energy of your abnormal nature diff --git a/Resources/Locale/en-US/ss14-ru/prototypes/entities/clothing/eyes/glasses.ftl b/Resources/Locale/en-US/ss14-ru/prototypes/entities/clothing/eyes/glasses.ftl index acc0ccdee6a..6ade83db158 100644 --- a/Resources/Locale/en-US/ss14-ru/prototypes/entities/clothing/eyes/glasses.ftl +++ b/Resources/Locale/en-US/ss14-ru/prototypes/entities/clothing/eyes/glasses.ftl @@ -11,7 +11,7 @@ ent-ClothingEyesGlasses = glasses ent-ClothingEyesGlassesJensen = jensen glasses .desc = A pair of yellow tinted folding glasses. You never asked for these. ent-ClothingEyesGlassesJamjar = jamjar glasses - .desc = Also known as Virginity Protectors. + .desc = These retro glasses remind you of a simpler time. ent-ClothingEyesGlassesOutlawGlasses = outlaw glasses .desc = A must for every self-respecting undercover agent. ent-ClothingEyesGlassesCheapSunglasses = cheap sunglasses diff --git a/Resources/Locale/en-US/ss14-ru/prototypes/entities/clothing/head/hoods.ftl b/Resources/Locale/en-US/ss14-ru/prototypes/entities/clothing/head/hoods.ftl index 35b4e350a3b..934c1105926 100644 --- a/Resources/Locale/en-US/ss14-ru/prototypes/entities/clothing/head/hoods.ftl +++ b/Resources/Locale/en-US/ss14-ru/prototypes/entities/clothing/head/hoods.ftl @@ -106,3 +106,5 @@ ent-ClothingHeadHatHoodWinterColorWhite = white winter coat hood .desc = { ent-ClothingHeadHatHoodWinterBase.desc } ent-ClothingHeadHatHoodWinterColorYellow = yellow winter coat hood .desc = { ent-ClothingHeadHatHoodWinterBase.desc } +ent-ClothingHeadHatHoodVoidCloak = void cloak hood + .desc = The hood of a void cloak. For those who have gone to the dark side of the force. diff --git a/Resources/Locale/en-US/ss14-ru/prototypes/entities/markers/spawners/mobs.ftl b/Resources/Locale/en-US/ss14-ru/prototypes/entities/markers/spawners/mobs.ftl index b396b5e730c..2d91254a973 100644 --- a/Resources/Locale/en-US/ss14-ru/prototypes/entities/markers/spawners/mobs.ftl +++ b/Resources/Locale/en-US/ss14-ru/prototypes/entities/markers/spawners/mobs.ftl @@ -4,6 +4,9 @@ ent-SpawnMobCockroach = Cockroach Spawner .desc = { ent-MarkerBase.desc } ent-SpawnMobCorgi = HoP Corgi Spawner .desc = { ent-MarkerBase.desc } +ent-SpawnMobCorgiMouse = Dev Mouse Spawner + .suffix = Admeme + .desc = { ent-MarkerBase.desc } ent-SpawnMobPossumMorty = Possum Morty Spawner .desc = { ent-MarkerBase.desc } ent-SpawnMobRaccoonMorticia = Raccoon Morticia Spawner diff --git a/Resources/Locale/en-US/ss14-ru/prototypes/entities/markers/spawners/random/anomaly.ftl b/Resources/Locale/en-US/ss14-ru/prototypes/entities/markers/spawners/random/anomaly.ftl index c7bc133f9be..ddeec7359a5 100644 --- a/Resources/Locale/en-US/ss14-ru/prototypes/entities/markers/spawners/random/anomaly.ftl +++ b/Resources/Locale/en-US/ss14-ru/prototypes/entities/markers/spawners/random/anomaly.ftl @@ -2,3 +2,5 @@ ent-RandomAnomalySpawner = random anomaly spawner .desc = { ent-MarkerBase.desc } ent-RandomRockAnomalySpawner = { ent-MarkerBase } .desc = { ent-MarkerBase.desc } +ent-RandomAnomalyInjectorSpawner = { ent-MarkerBase } + .desc = { ent-MarkerBase.desc } diff --git a/Resources/Locale/en-US/ss14-ru/prototypes/entities/mobs/npcs/pets.ftl b/Resources/Locale/en-US/ss14-ru/prototypes/entities/mobs/npcs/pets.ftl index a90b970961c..572361cd54c 100644 --- a/Resources/Locale/en-US/ss14-ru/prototypes/entities/mobs/npcs/pets.ftl +++ b/Resources/Locale/en-US/ss14-ru/prototypes/entities/mobs/npcs/pets.ftl @@ -4,6 +4,8 @@ ent-MobCorgiIanOld = Old Ian .desc = Still the favorite pet corgi. Love his wheels. ent-MobCorgiLisa = Lisa .desc = Ian's favorite corgi. +ent-MobCorgiMouse = real mouse + .desc = It's 100% a real hungry mouse. ent-MobCorgiIanPup = Puppy Ian .desc = Favourite puppy corgi. Awww. ent-MobCatRuntime = Runtime diff --git a/Resources/Locale/en-US/ss14-ru/prototypes/entities/objects/consumable/food/produce.ftl b/Resources/Locale/en-US/ss14-ru/prototypes/entities/objects/consumable/food/produce.ftl index bb33fc22a0a..e2d935d236c 100644 --- a/Resources/Locale/en-US/ss14-ru/prototypes/entities/objects/consumable/food/produce.ftl +++ b/Resources/Locale/en-US/ss14-ru/prototypes/entities/objects/consumable/food/produce.ftl @@ -4,6 +4,8 @@ ent-FoodProduceBase = { ent-FoodInjectableBase } .desc = { ent-FoodInjectableBase.desc } ent-WheatBushel = wheat bushel .desc = Sigh... wheat... a-grain? +ent-MeatwheatBushel = meatwheat bushel + .desc = Some blood-drenched wheat stalks. You can crush them into what passes for meat if you squint hard enough. ent-OatBushel = oat bushel .desc = Eat oats, do squats. ent-Sugarcane = sugarcane @@ -46,6 +48,8 @@ ent-FoodLime = lime .desc = Cures Space Scurvy, allows you to act like a Space Pirate. ent-FoodOrange = orange .desc = Healthy, very orange. +ent-FoodExtradimensionalOrange = extradimensional orange + .desc = You can hardly wrap your head around this thing. ent-FoodPineapple = pineapple .desc = Mmm, tropical. ent-FoodPotato = potato @@ -123,6 +127,10 @@ ent-FoodWatermelon = watermelon .desc = Round green object that you can slice and eat. ent-FoodWatermelonSlice = watermelon slice .desc = Juicy green and red slice. +ent-FoodHolymelon = holymelon + .desc = The water within this melon has been blessed by some deity that's particularly fond of watermelon. +ent-FoodHolymelonSlice = holymelon slice + .desc = Juicy golden and red slice. ent-FoodGrape = grapes .desc = The food of emperors, Space France inhabitants (usually as wine) and soccer moms. One day it could be used in wine production for the bartender if he ever runs out. ent-FoodBerries = berries @@ -133,6 +141,8 @@ ent-FoodBungoPit = bungo pit .desc = { ent-FoodInjectableBase.desc } ent-FoodPeaPod = pea pod .desc = A duck's favorite treat! +ent-FoodWorldPeas = cluster of world peas + .desc = It's rumored to bring peace to any who consume it. ent-FoodPumpkin = pumpkin .desc = A large, orange... berry. Seriously. ent-FoodBluePumpkin = blue pumpkin diff --git a/Resources/Locale/en-US/ss14-ru/prototypes/entities/objects/devices/encryption_keys.ftl b/Resources/Locale/en-US/ss14-ru/prototypes/entities/objects/devices/encryption_keys.ftl index d8eb3711e8d..326fa23b23b 100644 --- a/Resources/Locale/en-US/ss14-ru/prototypes/entities/objects/devices/encryption_keys.ftl +++ b/Resources/Locale/en-US/ss14-ru/prototypes/entities/objects/devices/encryption_keys.ftl @@ -28,5 +28,7 @@ ent-EncryptionKeySyndie = blood-red encryption key .desc = An encryption key used by... wait... Who is the owner of this chip? ent-EncryptionKeyBinary = binary translator key .desc = An encryption key that translates binary signals used by silicons. +ent-EncryptionKeyBinarySyndicate = binary translator key + .desc = A syndicate encryption key that translates binary signals used by silicons. ent-EncryptionKeyFreelance = freelancer encryption key .desc = An encryption key used by freelancers, who may or may not have an affiliation. It looks like it's worn out. diff --git a/Resources/Locale/en-US/ss14-ru/prototypes/entities/objects/devices/station_beacon.ftl b/Resources/Locale/en-US/ss14-ru/prototypes/entities/objects/devices/station_beacon.ftl index 4dc876add7c..fa95fdaa0d4 100644 --- a/Resources/Locale/en-US/ss14-ru/prototypes/entities/objects/devices/station_beacon.ftl +++ b/Resources/Locale/en-US/ss14-ru/prototypes/entities/objects/devices/station_beacon.ftl @@ -15,6 +15,9 @@ ent-DefaultStationBeaconBridge = { ent-DefaultStationBeaconCommand } ent-DefaultStationBeaconVault = { ent-DefaultStationBeaconCommand } .suffix = Vault .desc = { ent-DefaultStationBeaconCommand.desc } +ent-DefaultStationBeaconGateway = { ent-DefaultStationBeaconCommand } + .suffix = Gateway + .desc = { ent-DefaultStationBeaconCommand.desc } ent-DefaultStationBeaconCaptainsQuarters = { ent-DefaultStationBeaconCommand } .suffix = Captain's Quarters .desc = { ent-DefaultStationBeaconCommand.desc } diff --git a/Resources/Locale/en-US/ss14-ru/prototypes/entities/objects/fun/immovable_rod.ftl b/Resources/Locale/en-US/ss14-ru/prototypes/entities/objects/fun/immovable_rod.ftl index 6524297c2fc..4677c7a3074 100644 --- a/Resources/Locale/en-US/ss14-ru/prototypes/entities/objects/fun/immovable_rod.ftl +++ b/Resources/Locale/en-US/ss14-ru/prototypes/entities/objects/fun/immovable_rod.ftl @@ -29,3 +29,5 @@ ent-ImmovableRodThrongler = immovable throngler .desc = If you catch it, you can keep it. ent-ImmovableRodGibstick = immovable gibstick .desc = What did you expect? +ent-ImmovableRodWeh = immovable weh + .desc = WEH! diff --git a/Resources/Locale/en-US/ss14-ru/prototypes/entities/objects/fun/toys.ftl b/Resources/Locale/en-US/ss14-ru/prototypes/entities/objects/fun/toys.ftl index 2fe7a04f5c5..77d65330eec 100644 --- a/Resources/Locale/en-US/ss14-ru/prototypes/entities/objects/fun/toys.ftl +++ b/Resources/Locale/en-US/ss14-ru/prototypes/entities/objects/fun/toys.ftl @@ -125,3 +125,5 @@ ent-CrazyGlue = crazy glue .desc = A bottle of crazy glue manufactured by Honk! Co. ent-NewtonCradle = newton cradle .desc = A device bored paper pushers use to remind themselves that time did not stop yet. Contains gravity. +ent-RubberChicken = rubber chicken + .desc = A stress inducing parody of nature's most delectable avian. diff --git a/Resources/Locale/en-US/ss14-ru/prototypes/entities/objects/specific/hydroponics/seeds.ftl b/Resources/Locale/en-US/ss14-ru/prototypes/entities/objects/specific/hydroponics/seeds.ftl index 69eea984a04..7188ee75a4d 100644 --- a/Resources/Locale/en-US/ss14-ru/prototypes/entities/objects/specific/hydroponics/seeds.ftl +++ b/Resources/Locale/en-US/ss14-ru/prototypes/entities/objects/specific/hydroponics/seeds.ftl @@ -2,6 +2,8 @@ ent-SeedBase = { ent-BaseItem } .desc = { ent-BaseItem.desc } ent-WheatSeeds = packet of wheat seeds .desc = { ent-SeedBase.desc } +ent-MeatwheatSeeds = packet of meatwheat seeds + .desc = If you ever wanted to drive a vegetarian to insanity, here's how. ent-OatSeeds = packet of oat seeds .desc = { ent-SeedBase.desc } ent-BananaSeeds = packet of banana seeds @@ -24,6 +26,8 @@ ent-LimeSeeds = packet of lime seeds .desc = { ent-SeedBase.desc } ent-OrangeSeeds = packet of orange seeds .desc = { ent-SeedBase.desc } +ent-ExtradimensionalOrangeSeeds = packet of extradimensional orange seeds + .desc = Polygonal seeds. ent-PineappleSeeds = packet of pineapple seeds .desc = { ent-SeedBase.desc } ent-PotatoSeeds = packet of potato seeds @@ -106,6 +110,8 @@ ent-OnionRedSeeds = packet of red onion seeds .desc = Purple despite the name. ent-WatermelonSeeds = packet of watermelon seeds .desc = { ent-SeedBase.desc } +ent-HolymelonSeeds = packet of holymelon seeds + .desc = { ent-SeedBase.desc } ent-GrapeSeeds = packet of grape seeds .desc = { ent-SeedBase.desc } ent-CocoaSeeds = packet of cocoa seeds @@ -116,6 +122,8 @@ ent-BungoSeeds = packet of bungo seeds .desc = Don't eat the pits. ent-PeaSeeds = packet of pea pods .desc = These humble plants were once a vital part in the study of genetics. +ent-WorldPeaSeeds = packet of world pea seeds + .desc = These rather large seeds give off a soothing blue glow. ent-PumpkinSeeds = packet of pumpkin seeds .desc = { ent-SeedBase.desc } ent-BluePumpkinSeeds = packet of blue pumpkin seeds diff --git a/Resources/Locale/en-US/ss14-ru/prototypes/entities/structures/doors/airlocks/access.ftl b/Resources/Locale/en-US/ss14-ru/prototypes/entities/structures/doors/airlocks/access.ftl index 0c7955fad48..63756d4cbad 100644 --- a/Resources/Locale/en-US/ss14-ru/prototypes/entities/structures/doors/airlocks/access.ftl +++ b/Resources/Locale/en-US/ss14-ru/prototypes/entities/structures/doors/airlocks/access.ftl @@ -190,6 +190,9 @@ ent-AirlockMiningGlassLocked = { ent-AirlockMiningGlass } ent-AirlockChemistryGlassLocked = { ent-AirlockChemistryGlass } .suffix = Chemistry, Locked .desc = { ent-AirlockChemistryGlass.desc } +ent-AirlockMedicalMorgueGlassLocked = { ent-AirlockMedicalGlass } + .suffix = Morgue, Locked + .desc = { ent-AirlockMedicalGlass.desc } ent-AirlockMedicalGlassLocked = { ent-AirlockMedicalGlass } .suffix = Medical, Locked .desc = { ent-AirlockMedicalGlass.desc } diff --git a/Resources/Locale/en-US/ss14-ru/prototypes/entities/structures/machines/vending_machines.ftl b/Resources/Locale/en-US/ss14-ru/prototypes/entities/structures/machines/vending_machines.ftl index 7171579fd5b..c106115d69e 100644 --- a/Resources/Locale/en-US/ss14-ru/prototypes/entities/structures/machines/vending_machines.ftl +++ b/Resources/Locale/en-US/ss14-ru/prototypes/entities/structures/machines/vending_machines.ftl @@ -6,6 +6,8 @@ ent-VendingMachineAmmo = liberation station .desc = An overwhelming amount of ancient patriotism washes over you just by looking at the machine. ent-VendingMachineBooze = Booze-O-Mat .desc = A technological marvel, supposedly able to mix just the mixture you'd like to drink the moment you ask for one. +ent-VendingMachineBoozeSyndicate = Bruise-O-Mat + .desc = A refurbished Booze-O-Mat for boosting operative morale. An imprint of a blood-red hardsuit is visible on one side, and the paint seems ashed off on the other side. ent-VendingMachineCart = PTech .desc = PTech vending! Providing a ROBUST selection of PDAs, cartridges, and anything else a dull paper pusher needs! ent-VendingMachineChefvend = ChefVend diff --git a/Resources/Locale/en-US/ss14-ru/prototypes/entities/structures/specific/anomaly/anomaly_injections.ftl b/Resources/Locale/en-US/ss14-ru/prototypes/entities/structures/specific/anomaly/anomaly_injections.ftl new file mode 100644 index 00000000000..52a8391fade --- /dev/null +++ b/Resources/Locale/en-US/ss14-ru/prototypes/entities/structures/specific/anomaly/anomaly_injections.ftl @@ -0,0 +1,22 @@ +ent-AnomalyInjectionBase = { "" } + .desc = { "" } +ent-AnomalyInjectionPyroclastic = { ent-AnomalyInjectionBase } + .desc = { ent-AnomalyInjectionBase.desc } +ent-AnomalyInjectionElectric = { ent-AnomalyInjectionBase } + .desc = { ent-AnomalyInjectionBase.desc } +ent-AnomalyInjectionShadow = { ent-AnomalyInjectionBase } + .desc = { ent-AnomalyInjectionBase.desc } +ent-AnomalyInjectionIce = { ent-AnomalyInjectionBase } + .desc = { ent-AnomalyInjectionBase.desc } +ent-AnomalyInjectionFlora = { ent-AnomalyInjectionBase } + .desc = { ent-AnomalyInjectionBase.desc } +ent-AnomalyInjectionBluespace = { ent-AnomalyInjectionBase } + .desc = { ent-AnomalyInjectionBase.desc } +ent-AnomalyInjectionFlesh = { ent-AnomalyInjectionBase } + .desc = { ent-AnomalyInjectionBase.desc } +ent-AnomalyInjectionGravity = { ent-AnomalyInjectionBase } + .desc = { ent-AnomalyInjectionBase.desc } +ent-AnomalyInjectionTech = { ent-AnomalyInjectionBase } + .desc = { ent-AnomalyInjectionBase.desc } +ent-AnomalyInjectionRock = { ent-AnomalyInjectionBase } + .desc = { ent-AnomalyInjectionBase.desc } diff --git a/Resources/Locale/en-US/ss14-ru/prototypes/entities/structures/specific/anomaly/anomaly_injectors.ftl b/Resources/Locale/en-US/ss14-ru/prototypes/entities/structures/specific/anomaly/anomaly_injectors.ftl new file mode 100644 index 00000000000..b8243e85127 --- /dev/null +++ b/Resources/Locale/en-US/ss14-ru/prototypes/entities/structures/specific/anomaly/anomaly_injectors.ftl @@ -0,0 +1,32 @@ +ent-BaseAnomalyInjector = anomaly injector + .desc = { ent-MarkerBase.desc } +ent-AnomalyTrapPyroclastic = { ent-BaseAnomalyInjector } + .suffix = Pyroclastic + .desc = { ent-BaseAnomalyInjector.desc } +ent-AnomalyTrapElectricity = { ent-BaseAnomalyInjector } + .suffix = Electricity + .desc = { ent-BaseAnomalyInjector.desc } +ent-AnomalyTrapShadow = { ent-BaseAnomalyInjector } + .suffix = Shadow + .desc = { ent-BaseAnomalyInjector.desc } +ent-AnomalyTrapIce = { ent-BaseAnomalyInjector } + .suffix = Ice + .desc = { ent-BaseAnomalyInjector.desc } +ent-AnomalyTrapFlora = { ent-BaseAnomalyInjector } + .suffix = Flora + .desc = { ent-BaseAnomalyInjector.desc } +ent-AnomalyTrapBluespace = { ent-BaseAnomalyInjector } + .suffix = Bluespace + .desc = { ent-BaseAnomalyInjector.desc } +ent-AnomalyTrapFlesh = { ent-BaseAnomalyInjector } + .suffix = Flesh + .desc = { ent-BaseAnomalyInjector.desc } +ent-AnomalyTrapGravity = { ent-BaseAnomalyInjector } + .suffix = Gravity + .desc = { ent-BaseAnomalyInjector.desc } +ent-AnomalyTrapTech = { ent-BaseAnomalyInjector } + .suffix = Tech + .desc = { ent-BaseAnomalyInjector.desc } +ent-AnomalyTrapRock = { ent-BaseAnomalyInjector } + .suffix = Rock + .desc = { ent-BaseAnomalyInjector.desc } diff --git a/Resources/Locale/en-US/ss14-ru/prototypes/entities/structures/wallmounts/intercom.ftl b/Resources/Locale/en-US/ss14-ru/prototypes/entities/structures/wallmounts/intercom.ftl index ae2decfa6e8..da16942a779 100644 --- a/Resources/Locale/en-US/ss14-ru/prototypes/entities/structures/wallmounts/intercom.ftl +++ b/Resources/Locale/en-US/ss14-ru/prototypes/entities/structures/wallmounts/intercom.ftl @@ -7,6 +7,8 @@ ent-IntercomConstructed = { ent-BaseIntercom } .desc = { ent-BaseIntercom.desc } ent-Intercom = { ent-IntercomConstructed } .desc = { ent-IntercomConstructed.desc } +ent-BaseIntercomSecure = { ent-Intercom } + .desc = { ent-Intercom.desc } ent-IntercomCommon = { ent-Intercom } .suffix = Common .desc = { ent-Intercom.desc } diff --git a/Resources/Locale/en-US/ss14-ru/prototypes/gamerules/events.ftl b/Resources/Locale/en-US/ss14-ru/prototypes/gamerules/events.ftl index 2affaa913be..f383f1ba5db 100644 --- a/Resources/Locale/en-US/ss14-ru/prototypes/gamerules/events.ftl +++ b/Resources/Locale/en-US/ss14-ru/prototypes/gamerules/events.ftl @@ -36,6 +36,8 @@ ent-VentClog = { ent-BaseStationEventLongDelay } .desc = { ent-BaseStationEventLongDelay.desc } ent-SlimesSpawn = { ent-BaseStationEventShortDelay } .desc = { ent-BaseStationEventShortDelay.desc } +ent-SnakeSpawn = { ent-BaseStationEventShortDelay } + .desc = { ent-BaseStationEventShortDelay.desc } ent-SpiderSpawn = { ent-BaseStationEventShortDelay } .desc = { ent-BaseStationEventShortDelay.desc } ent-SpiderClownSpawn = { ent-BaseStationEventShortDelay } diff --git a/Resources/Locale/ru-RU/accent/accents.ftl b/Resources/Locale/ru-RU/accent/accents.ftl index b552948fd19..6550856896a 100644 --- a/Resources/Locale/ru-RU/accent/accents.ftl +++ b/Resources/Locale/ru-RU/accent/accents.ftl @@ -107,3 +107,9 @@ accent-words-nymph-1 = Чирик! accent-words-nymph-2 = Чурр... accent-words-nymph-3 = Чипи? accent-words-nymph-4 = Шрруп! +# TomatoKiller +accent-words-tomato-1 = Totato! +accent-words-tomato-2 = Trotect +accent-words-tomato-3 = Mastet? +accent-words-tomato-4 = Reaty! +accent-words-tomato-5 = Water... diff --git a/Resources/Locale/ru-RU/accent/skeleton.ftl b/Resources/Locale/ru-RU/accent/skeleton.ftl new file mode 100644 index 00000000000..4f198c529d9 --- /dev/null +++ b/Resources/Locale/ru-RU/accent/skeleton.ftl @@ -0,0 +1,24 @@ +accent-skeleton-words-1 = fuck you +accent-skeleton-words-replace-1 = I've got a BONE to pick with you +accent-skeleton-words-2 = fucked +accent-skeleton-words-replace-2 = boned +accent-skeleton-words-3 = fuck +accent-skeleton-words-3-2 = fck +accent-skeleton-words-3-3 = shit +accent-skeleton-words-replace-3 = RATTLE RATTLE +accent-skeleton-words-4 = definitely +accent-skeleton-words-4-2 = absolutely +accent-skeleton-words-replace-4 = make no bones about it +accent-skeleton-words-5 = afraid +accent-skeleton-words-5-2 = scared +accent-skeleton-words-5-3 = spooked +accent-skeleton-words-5-4 = shocked +accent-skeleton-words-replace-5 = rattled +accent-skeleton-words-6 = killed +accent-skeleton-words-replace-6 = skeletonized +accent-skeleton-words-7 = humorous +accent-skeleton-words-replace-7 = humerus +accent-skeleton-words-8 = to be a +accent-skeleton-words-replace-8 = tibia +accent-skeleton-words-9 = under +accent-skeleton-words-replace-9 = ulna diff --git a/Resources/Locale/ru-RU/actions/ui/actionslot.ftl b/Resources/Locale/ru-RU/actions/ui/actionslot.ftl index 18c5a558a69..0c6d1bc6ad8 100644 --- a/Resources/Locale/ru-RU/actions/ui/actionslot.ftl +++ b/Resources/Locale/ru-RU/actions/ui/actionslot.ftl @@ -1 +1,2 @@ ui-actionslot-charges = Осталось использований: { $charges } +ui-actionslot-duration = [color=#a10505] { $duration } sec cooldown ({ $timeLeft } sec remaining)[/color] diff --git a/Resources/Locale/ru-RU/advertisements/vending/bruiseomat.ftl b/Resources/Locale/ru-RU/advertisements/vending/bruiseomat.ftl new file mode 100644 index 00000000000..da10bcfeb04 --- /dev/null +++ b/Resources/Locale/ru-RU/advertisements/vending/bruiseomat.ftl @@ -0,0 +1,43 @@ +advertisement-bruiseomat-1 = I VOTE WAROPS!!! +advertisement-bruiseomat-2 = Who has TC? +advertisement-bruiseomat-3 = Did anyone buy an EMAG? +advertisement-bruiseomat-4 = I wanna go back to my home station... +advertisement-bruiseomat-5 = Beware of the Mime and Clown. BEWARE! +advertisement-bruiseomat-6 = A nuke a day keeps the deathsquad at bay! +advertisement-bruiseomat-7 = You'll never be able to match MY mixing, Agent! +advertisement-bruiseomat-8 = Thirsting for blood? I got you covered! +advertisement-bruiseomat-9 = If they didn't want us to blow up the station, then why would they leave the disk so unsecured? +advertisement-bruiseomat-10 = They say an eye for an eye makes the whole world blind. So try a nuke instead! +advertisement-bruiseomat-11 = I hunger for blood! +advertisement-bruiseomat-12 = Drink up before the mission! +advertisement-bruiseomat-13 = Man, I didn't know I got moved back to Cadet City! +advertisement-bruiseomat-14 = Sicker than your average Booze-O-Mat! +advertisement-bruiseomat-15 = Nuke ops will continue until robustness improves. +thankyou-bruiseomat-1 = Good luck, schmuck! You're gonna need it! +thankyou-bruiseomat-2 = Show 'em the Gorlex Style! +thankyou-bruiseomat-3 = Don't forget to stay hydrated! +thankyou-bruiseomat-4 = You noted down the codes, right? +thankyou-bruiseomat-5 = Don't forget the nuke! +thankyou-bruiseomat-6 = I hope those are noslips. +thankyou-bruiseomat-7 = Please let this be a normal team... +thankyou-bruiseomat-8 = Seems like the station isn't the only thing getting hammered today. +thankyou-bruiseomat-9 = What the hell did you buy? +thankyou-bruiseomat-10 = Give it up for the flukeops professionals! +thankyou-bruiseomat-11 = Death to NanoTrasen!!! +thankyou-bruiseomat-12 = Really? That's your plan? +thankyou-bruiseomat-13 = In my endless life, never have I ever seen that loadout. +thankyou-bruiseomat-14 = Get that captain! +thankyou-bruiseomat-15 = Don't run off by yourself, now! +thankyou-bruiseomat-16 = Y'all are taking too long! +thankyou-bruiseomat-17 = They won't see that coming! +thankyou-bruiseomat-18 = Remember your pinpointer! +thankyou-bruiseomat-19 = See you soon! Or maybe never again, that one's more likely! +thankyou-bruiseomat-20 = Rescue another one of me! I need a friend! +thankyou-bruiseomat-21 = You're going to sober up before the mission, right? +thankyou-bruiseomat-22 = 5 telecrystal says you won't make it to the shuttle before you fall over. +thankyou-bruiseomat-23 = The soda fountain's over there, lightweight. +thankyou-bruiseomat-24 = Did you spend your TC on cat ears? +thankyou-bruiseomat-25 = Really? That's what you wanted to drink? +thankyou-bruiseomat-26 = Take a shot, give a shot! +thankyou-bruiseomat-27 = How many drinks have you had now? I've lost count. +thankyou-bruiseomat-28 = When the bosses say "die trying" they mean dying in BATTLE, not at the bar. diff --git a/Resources/Locale/ru-RU/anomaly/inner_anomaly.ftl b/Resources/Locale/ru-RU/anomaly/inner_anomaly.ftl new file mode 100644 index 00000000000..2069600bdbc --- /dev/null +++ b/Resources/Locale/ru-RU/anomaly/inner_anomaly.ftl @@ -0,0 +1,15 @@ +inner-anomaly-start-message-pyro = You can feel the insane flame inside of you. You became the host of a pyroclastic anomaly. +inner-anomaly-start-message-shock = Lightning bolts quivering at your fingertips! You became the host of a electric anomaly. +inner-anomaly-start-message-shadow = There's an impenetrable darkness oozing out of you... You became the host of a shadow anomaly. +inner-anomaly-start-message-frost = The icy frost is binding your bones. You became the host of a ice anomaly. +inner-anomaly-start-message-flora = Leaves and flowers sprout through your skin! You became the host of a floral anomaly. +inner-anomaly-start-message-bluespace = Your thoughts are racing like mad! You became the host of a bluespace anomaly. +inner-anomaly-start-message-flesh = Your body is growing frantically. You became the host of a flesh anomaly. +inner-anomaly-start-message-grav = Everything becames unnaturally heavy and light at the same time... You became the host of a gravity anomaly. +inner-anomaly-start-message-tech = Your head is buzzing with the amount of chaotic information! You became the host of a tech anomaly. +inner-anomaly-start-message-rock = The crystals are growing through your bones! You became the host of a rock anomaly. +inner-anomaly-end-message = The abnormal activity within you disappears without a trace.... +inner-anomaly-severity-info-50 = You feel that the anomaly is taking over half your body. +inner-anomaly-severity-info-75 = You feel that the anomaly is taking over a large part of your body. +inner-anomaly-severity-info-90 = You feel that the anomaly has almost completely taken over your body. +inner-anomaly-severity-info-100 = The anomaly inside you is growing uncontrollably, causing immense pain, and tearing you apart! diff --git a/Resources/Locale/ru-RU/communications/communications-console-component.ftl b/Resources/Locale/ru-RU/communications/communications-console-component.ftl index fcf48ebce00..bdf8f9a52e2 100644 --- a/Resources/Locale/ru-RU/communications/communications-console-component.ftl +++ b/Resources/Locale/ru-RU/communications/communications-console-component.ftl @@ -21,3 +21,4 @@ comms-console-announcement-unknown-sender = Неизвестный comms-console-announcement-title-station = Консоль связи comms-console-announcement-title-centcom = Центральное командование comms-console-announcement-title-nukie = Ядерные оперативники Синдиката +comms-console-announcement-title-station-ai = Station AI diff --git a/Resources/Locale/ru-RU/flavors/flavor-profiles.ftl b/Resources/Locale/ru-RU/flavors/flavor-profiles.ftl index efbab8dbe86..cb8c77a260c 100644 --- a/Resources/Locale/ru-RU/flavors/flavor-profiles.ftl +++ b/Resources/Locale/ru-RU/flavors/flavor-profiles.ftl @@ -179,6 +179,9 @@ flavor-complex-violets = как фиалки flavor-complex-pyrotton = как горящий рот flavor-complex-mothballs = как нафталиновые шарики flavor-complex-paint-thinner = как растворитель для краски +flavor-complex-numbing-tranquility = like numbing tranquility +flavor-complex-true-nature = like the true nature of reality +flavor-complex-false-meat = not entirely unlike meat flavor-complex-paper = как кашеобразная масса flavor-complex-compressed-meat = как спрессованное мясо flavor-complex-alcohol = как алкоголь diff --git a/Resources/Locale/ru-RU/ghost/roles/ghost-role-component.ftl b/Resources/Locale/ru-RU/ghost/roles/ghost-role-component.ftl index 431c657d2fd..ff151739d95 100644 --- a/Resources/Locale/ru-RU/ghost/roles/ghost-role-component.ftl +++ b/Resources/Locale/ru-RU/ghost/roles/ghost-role-component.ftl @@ -229,3 +229,5 @@ ghost-role-information-syndie-disaster-victim-name = Жертва катастр ghost-role-information-syndie-disaster-victim-description = Вы - обычный пассажир со станции Синдиката. К несчастью, спасательная капсула закинула вас во вражеский сектор... ghost-role-information-artifact-name = Разумный артефакт ghost-role-information-artifact-description = Осуществляйте свои инопланетные прихоти. Принудительно активируйте свои узлы во благо или во зло. +ghost-role-information-tomatokiller-name = Tomato killer +ghost-role-information-tomatokiller-description = This little tomato will serve the botanist for the rest of his life... that is, a couple of minutes diff --git a/Resources/Locale/ru-RU/guardian/guardian.ftl b/Resources/Locale/ru-RU/guardian/guardian.ftl index 8e387d8c90f..c80bbe4f095 100644 --- a/Resources/Locale/ru-RU/guardian/guardian.ftl +++ b/Resources/Locale/ru-RU/guardian/guardian.ftl @@ -8,6 +8,7 @@ guardian-activator-empty-examine = [color=#ba1919]Инъектор израсх guardian-activator-invalid-target = Только гуманоиды подходят для инъекции! guardian-no-soul = У вашего стража нет души. guardian-available = У вашего стража теперь есть душа. +guardian-inside-container = There's no room to release your guardian! ## Guardian entity specific diff --git a/Resources/Locale/ru-RU/markings/gauze.ftl b/Resources/Locale/ru-RU/markings/gauze.ftl index c8e9ea3c9c4..a6a54d81f35 100644 --- a/Resources/Locale/ru-RU/markings/gauze.ftl +++ b/Resources/Locale/ru-RU/markings/gauze.ftl @@ -30,6 +30,8 @@ marking-GauzeUpperLegRight-gauze_upperleg_r = Бинт, Перевязь бед marking-GauzeUpperLegRight = Бинт, Перевязь бедра (Правый) marking-GauzeBlindfold-gauze_blindfold = Бинт, Повязка на оба глаза marking-GauzeBlindfold = Бинт, Повязка на глаза +marking-GauzeHead-gauze_head = Gauze Head Wrap +marking-GauzeHead = Gauze Head Wrap marking-GauzeLizardBlindfold-gauze_lizard_blindfold = Бинт, Повязка на глаза marking-GauzeLizardBlindfold = Бинт, Повязка на глаза marking-GauzeLizardFootRight-gauze_lizard_foot_r = Бинт, Перевязь стопы (Правый) diff --git a/Resources/Locale/ru-RU/mech/mech.ftl b/Resources/Locale/ru-RU/mech/mech.ftl index 52cd95e0dea..c98684e8538 100644 --- a/Resources/Locale/ru-RU/mech/mech.ftl +++ b/Resources/Locale/ru-RU/mech/mech.ftl @@ -11,3 +11,4 @@ mech-energy-display = Энергия: { $amount }% mech-energy-missing = Энергия: ОТСУТСТВУЕТ mech-slot-display = Доступно слотов: { $amount } mech-no-enter = Вы не можете пилотировать это. +mech-eject-pilot-alert = { $user } is pulling the pilot out of the { $item }! diff --git a/Resources/Locale/ru-RU/mind/commands/rename-command.ftl b/Resources/Locale/ru-RU/mind/commands/rename-command.ftl new file mode 100644 index 00000000000..cdb6f97c1fb --- /dev/null +++ b/Resources/Locale/ru-RU/mind/commands/rename-command.ftl @@ -0,0 +1,5 @@ +cmd-rename-desc = Renames an entity and its cloner entries, ID cards, and PDAs. +cmd-rename-help = rename +cmd-rename-too-long = Name is too long. +cmd-rename-not-found = Can't find username/uid: { $target } +cmd-rename-no-entity = { $target } does not have an entity. diff --git a/Resources/Locale/ru-RU/navmap-beacons/station-beacons.ftl b/Resources/Locale/ru-RU/navmap-beacons/station-beacons.ftl index f455aabc7d9..c365c1ea398 100644 --- a/Resources/Locale/ru-RU/navmap-beacons/station-beacons.ftl +++ b/Resources/Locale/ru-RU/navmap-beacons/station-beacons.ftl @@ -2,6 +2,7 @@ station-beacon-general = Общий station-beacon-command = Командование station-beacon-bridge = Мостик station-beacon-vault = Хранилище +station-beacon-gateway = Gateway station-beacon-captain = Капитан station-beacon-hop = Кабинет ГП station-beacon-security = Служба безопасности diff --git a/Resources/Locale/ru-RU/nutrition/components/food-sequence.ftl b/Resources/Locale/ru-RU/nutrition/components/food-sequence.ftl index d920ea48220..3144fd4e622 100644 --- a/Resources/Locale/ru-RU/nutrition/components/food-sequence.ftl +++ b/Resources/Locale/ru-RU/nutrition/components/food-sequence.ftl @@ -14,6 +14,7 @@ food-sequence-content-salami = салями food-sequence-content-slime = слаймом food-sequence-content-clown = клоуном food-sequence-content-pea = бобами +food-sequence-content-world-pea = world pea food-sequence-content-bungo = бунго food-sequence-content-banana = бананом food-sequence-content-mimana = миманом @@ -64,6 +65,7 @@ food-sequence-content-glasstle = стеклополохом food-sequence-content-gatfruit = гатфруктом food-sequence-content-koibean = коибобами food-sequence-content-watermelon = арбузом +food-sequence-content-holymelon = holymelon food-sequence-content-cannabis = коноплёй food-sequence-content-rainbow-cannabis = радужной коноплёй food-sequence-content-tobacco = табаком @@ -105,6 +107,7 @@ food-sequence-burger-content-rice = рис food-sequence-burger-content-soy = сой food-sequence-burger-content-koibean = кои food-sequence-burger-content-watermelon = арбуз +food-sequence-burger-content-holymelon = holy food-sequence-burger-content-cannabis = смех food-sequence-burger-content-rainbow-cannabis = СМЕХ food-sequence-burger-content-tobacco = табако @@ -112,6 +115,8 @@ food-sequence-burger-content-suppermatter = супер food-sequence-burger-content-hamster = хомяко food-sequence-burger-content-berries = ягод food-sequence-burger-content-spacemans-trumpet = космотруб +food-sequence-burger-content-extradimensional-orange = 3d +food-sequence-burger-content-world-pea = peace # TACO diff --git a/Resources/Locale/ru-RU/objectives/conditions/steal-target-groups.ftl b/Resources/Locale/ru-RU/objectives/conditions/steal-target-groups.ftl new file mode 100644 index 00000000000..7436080b389 --- /dev/null +++ b/Resources/Locale/ru-RU/objectives/conditions/steal-target-groups.ftl @@ -0,0 +1,60 @@ +# Traitor single items +steal-target-groups-hypospray = hypospray +steal-target-groups-handheld-crew-monitor = handheld crew monitor +steal-target-groups-clothing-outer-hardsuit-rd = experimental research hardsuit +steal-target-groups-hand-teleporter = hand teleporter +steal-target-groups-clothing-shoes-boots-mag-adv = advanced magboots +steal-target-groups-box-folder-qm-clipboard = requisition digi-board +steal-target-groups-food-meat-corgi = prime-cut corgi meat +steal-target-groups-captain-id-card = captain ID card +steal-target-groups-jetpack-captain-filled = captain's jetpack +steal-target-groups-weapon-antique-laser = antique laser pistol +steal-target-groups-nuke-disk = nuclear authentication disk +steal-target-groups-weapon-energy-shot-gun = energy shotgun +# Thief Collection +steal-target-groups-figurines = figurine +steal-target-groups-heads-cloaks = head's cloak +steal-target-groups-heads-bedsheets = head's bedsheet +steal-target-groups-stamps = stamp +steal-target-groups-door-remotes = door remote +steal-target-groups-encryption-keys = encryption key +steal-target-groups-technology-disks = technology disk +steal-target-groups-id-cards = ID Card +steal-target-groups-lamps = LAMP +# Thief single item +steal-target-groups-forensic-scanner = forensic scanner +steal-target-groups-flippo-engraved-lighter = detective's Flippo engraved lighter +steal-target-groups-ammo-tech-fab-circuitboard = ammo techfab circuit board +steal-target-groups-clothing-head-hat-warden = warden's cap +steal-target-groups-clothing-outer-hardsuit-void-paramed = paramedic void suit +steal-target-groups-medical-tech-fab-circuitboard = medical techfab machine board +steal-target-groups-clothing-headset-alt-medical = chief medical officer's over-ear headset +steal-target-groups-research-and-development-server-machine-circuitboard = R&D server machine board +steal-target-groups-fire-axe = fireaxe +steal-target-groups-ame-part-flatpack = AME flatpack +steal-target-groups-salvage-expeditions-computer-circuitboard = salvage expeditions computer board +steal-target-groups-cargo-shuttle-console-circuitboard = cargo shuttle console board +steal-target-groups-clothing-eyes-hud-beer = beer goggles +steal-target-groups-bible = bible +steal-target-groups-clothing-neck-goldmedal = gold medal of crewmanship +steal-target-groups-clothing-neck-clownmedal = clown medal +# Thief structures +steal-target-groups-teg = teg generator part +steal-target-groups-freezer-heater = freezer or heater +steal-target-groups-altar-nanotrasen = nanotrasen altar (any) +steal-target-groups-nuclear-bomb = nuclear fission explosive +steal-target-groups-fax-machine-captain = captain long range fax machine +steal-target-groups-chem-dispenser = chemical dispenser +steal-target-groups-xeno-artifact = alien artifact +steal-target-groups-booze-dispenser = booze dispenser +steal-target-groups-plant-rd = "RD's potted plant" +steal-target-groups-toilet-golden-dirty-water = golden toilet +# Thief Animal +steal-target-groups-animal-named-cat = CMO's Cat +steal-target-groups-animal-ian = Ian +steal-target-groups-animal-mc-griff = McGriff +steal-target-groups-animal-walter = Walter +steal-target-groups-animal-morty = Morty +steal-target-groups-animal-renault = Renault +steal-target-groups-animal-shiva = Shiva +steal-target-groups-animal-tropico = Tropico diff --git a/Resources/Locale/ru-RU/preferences/loadout-groups.ftl b/Resources/Locale/ru-RU/preferences/loadout-groups.ftl index 89176261a58..55c5e3d6241 100644 --- a/Resources/Locale/ru-RU/preferences/loadout-groups.ftl +++ b/Resources/Locale/ru-RU/preferences/loadout-groups.ftl @@ -14,6 +14,7 @@ loadout-group-survival-syndicate = Github заставил меня переве loadout-group-breath-tool = Расозависимое дыхательное снаряжение loadout-group-tank-harness = Расозависимое снаряжение для выживания loadout-group-EVA-tank = Расозависимый газовый баллон +loadout-group-pocket-tank-double = Species-specific double emergency tank in pocket loadout-group-survival-mime = Мимский аварийный запас # Command loadout-group-captain-head = Капитан, голова diff --git a/Resources/Locale/ru-RU/replays/replays.ftl b/Resources/Locale/ru-RU/replays/replays.ftl index 6435f97883b..035d02ff179 100644 --- a/Resources/Locale/ru-RU/replays/replays.ftl +++ b/Resources/Locale/ru-RU/replays/replays.ftl @@ -10,6 +10,7 @@ replay-loading-failed = Не удалось загрузить повтор. Ошибка: { $reason } replay-loading-retry = Попробовать загрузить с большей допустимостью исключений - МОЖЕТ ВЫЗВАТЬ БАГИ! +replay-loading-cancel = Cancel # Main Menu replay-menu-subtext = Повторы replay-menu-load = Загрузить выбранный повтор diff --git a/Resources/Locale/ru-RU/round-end/round-end-system.ftl b/Resources/Locale/ru-RU/round-end/round-end-system.ftl index 28205a51f39..5c860c58c48 100644 --- a/Resources/Locale/ru-RU/round-end/round-end-system.ftl +++ b/Resources/Locale/ru-RU/round-end/round-end-system.ftl @@ -4,6 +4,7 @@ round-end-system-shuttle-called-announcement = Эвакуационный шат round-end-system-shuttle-already-called-announcement = Эвакуационный шаттл уже был отправлен. round-end-system-shuttle-auto-called-announcement = Процедура смены экипажа начата. Шаттл вызван. Он прибудет через: { $time } { $units }. round-end-system-shuttle-recalled-announcement = Эвакуационный шаттл был отозван. +round-end-system-shuttle-sender-announcement = Station round-end-system-round-restart-eta-announcement = Раунд перезапустится через { $time } { $units }... eta-units-minutes = минут eta-units-seconds = секунд diff --git a/Resources/Locale/ru-RU/seeds/seeds.ftl b/Resources/Locale/ru-RU/seeds/seeds.ftl index 27c1fe66f48..7d4fe72f87d 100644 --- a/Resources/Locale/ru-RU/seeds/seeds.ftl +++ b/Resources/Locale/ru-RU/seeds/seeds.ftl @@ -4,6 +4,8 @@ seeds-noun-spores = спор # Seeds seeds-wheat-name = пшеница seeds-wheat-display-name = стебли пшеницы +seeds-meatwheat-name = meatwheat +seeds-meatwheat-display-name = meatwheat stalks seeds-oat-name = овёс seeds-oat-display-name = стебли овса seeds-banana-name = банан @@ -24,6 +26,8 @@ seeds-lime-name = лайм seeds-lime-display-name = лаймовое дерево seeds-orange-name = апельсин seeds-orange-display-name = апельсиновое дерево +seeds-extradimensionalorange-name = extradimensional orange +seeds-extradimensionalorange-display-name = extradimensional orange trees seeds-pineapple-name = ананас seeds-pineapple-display-name = ананасовый куст seeds-potato-name = картофель @@ -108,6 +112,8 @@ seeds-koibean-name = коибобы seeds-koibean-display-name = коибобы seeds-watermelon-name = арбуз seeds-watermelon-display-name = арбуз +seeds-holymelon-name = holymelon +seeds-holymelon-display-name = holymelon vines seeds-grape-name = виноград seeds-grape-display-name = виноград seeds-cocoa-name = какао-бобы @@ -118,6 +124,8 @@ seeds-bungo-name = бунго seeds-bungo-display-name = куст бунго seeds-pea-name = горох seeds-pea-display-name = гороховая лоза +seeds-worldpea-name = world peas +seeds-worldpea-display-name = world pea vines seeds-pumpkin-name = тыква seeds-pumpkin-display-name = тыква seeds-blue-pumpkin-name = синяя тыква diff --git a/Resources/Locale/ru-RU/shuttles/emergency.ftl b/Resources/Locale/ru-RU/shuttles/emergency.ftl index a0a710ab5c9..89be9d1c63b 100644 --- a/Resources/Locale/ru-RU/shuttles/emergency.ftl +++ b/Resources/Locale/ru-RU/shuttles/emergency.ftl @@ -17,9 +17,9 @@ emergency-shuttle-command-launch-desc = Досрочно запускает эв # Emergency shuttle emergency-shuttle-left = Эвакуационный шаттл покинул станцию. Расчётное время прибытия шаттла на станцию Центкома - { $transitTime } секунд. emergency-shuttle-launch-time = Эвакуационный шаттл будет запущен через { $consoleAccumulator } секунд. -emergency-shuttle-docked = Эвакуационный шаттл пристыковался к станции { $location }, направление: { $direction }. Он улетит через { $time } секунд.{$extended} +emergency-shuttle-docked = Эвакуационный шаттл пристыковался к станции { $location }, направление: { $direction }. Он улетит через { $time } секунд.{ $extended } emergency-shuttle-good-luck = Эвакуационный шаттл не может найти станцию. Удачи. -emergency-shuttle-nearby = Эвакуационный шаттл не может найти подходящий стыковочный шлюз. Он дрейфует около станции, { $location }, направление: { $direction }. Он улетит через { $time } секунд.{$extended} +emergency-shuttle-nearby = Эвакуационный шаттл не может найти подходящий стыковочный шлюз. Он дрейфует около станции, { $location }, направление: { $direction }. Он улетит через { $time } секунд.{ $extended } emergency-shuttle-extended = { " " }Время до запуска было продлено в связи с непредвиденными обстоятельствами. # Emergency shuttle console popup / announcement emergency-shuttle-console-no-early-launches = Досрочный запуск отключён diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/actions/anomaly.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/actions/anomaly.ftl new file mode 100644 index 00000000000..2bfb1895263 --- /dev/null +++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/actions/anomaly.ftl @@ -0,0 +1,2 @@ +ent-ActionAnomalyPulse = Anomaly pulse + .desc = Release a pulse of energy of your abnormal nature diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/clothing/head/hoods.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/clothing/head/hoods.ftl index c832822a63b..94668c734f6 100644 --- a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/clothing/head/hoods.ftl +++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/clothing/head/hoods.ftl @@ -106,3 +106,5 @@ ent-ClothingHeadHatHoodWinterColorWhite = капюшон белой зимней .desc = { ent-ClothingHeadHatHoodWinterBase.desc } ent-ClothingHeadHatHoodWinterColorYellow = капюшон жёлтой зимней куртки .desc = { ent-ClothingHeadHatHoodWinterBase.desc } +ent-ClothingHeadHatHoodVoidCloak = void cloak hood + .desc = The hood of a void cloak. For those who have gone to the dark side of the force. diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/markers/spawners/mobs.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/markers/spawners/mobs.ftl index 5e7017da430..2de6d08c205 100644 --- a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/markers/spawners/mobs.ftl +++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/markers/spawners/mobs.ftl @@ -4,6 +4,9 @@ ent-SpawnMobCockroach = спавнер таракан .desc = { ent-MarkerBase.desc } ent-SpawnMobCat = спавнер кот .desc = { ent-MarkerBase.desc } +ent-SpawnMobCorgiMouse = Dev Mouse Spawner + .suffix = Admeme + .desc = { ent-MarkerBase.desc } ent-SpawnMobCorgi = спавнер корги .desc = { ent-MarkerBase.desc } ent-SpawnMobPossumMorty = спавнер опоссум Морти diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/markers/spawners/random/anomaly.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/markers/spawners/random/anomaly.ftl index 6b1ad504333..98b422c609f 100644 --- a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/markers/spawners/random/anomaly.ftl +++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/markers/spawners/random/anomaly.ftl @@ -2,3 +2,5 @@ ent-RandomAnomalySpawner = спавнер случайный аномалия .desc = { ent-MarkerBase.desc } ent-RandomRockAnomalySpawner = { ent-MarkerBase } .desc = { ent-MarkerBase.desc } +ent-RandomAnomalyInjectorSpawner = { ent-MarkerBase } + .desc = { ent-MarkerBase.desc } diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/mobs/npcs/pets.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/mobs/npcs/pets.ftl index c30a4ee007a..f815852150e 100644 --- a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/mobs/npcs/pets.ftl +++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/mobs/npcs/pets.ftl @@ -4,6 +4,8 @@ ent-MobCorgiIanOld = Старый Иан .desc = Всё ещё любимый домашний корги. Любит свои колёса. ent-MobCorgiLisa = Лиза .desc = Любимая корги Иана. +ent-MobCorgiMouse = real mouse + .desc = It's 100% a real hungry mouse. ent-MobCorgiIanPup = щенок Иан .desc = Любимый щенок корги. Аввв. ent-MobCatRuntime = Рантайм diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/consumable/food/produce.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/consumable/food/produce.ftl index 19bbd40e540..cdbd922934c 100644 --- a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/consumable/food/produce.ftl +++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/consumable/food/produce.ftl @@ -4,6 +4,8 @@ ent-FoodProduceBase = { ent-FoodInjectableBase } .desc = { ent-FoodInjectableBase.desc } ent-WheatBushel = сноп пшеницы .desc = Как правило, не лишён здравого зерна. +ent-MeatwheatBushel = meatwheat bushel + .desc = Some blood-drenched wheat stalks. You can crush them into what passes for meat if you squint hard enough. ent-OatBushel = сноп овса .desc = Ешьте овсянку, делайте зарядку. ent-Sugarcane = сахарный тростник @@ -46,6 +48,8 @@ ent-FoodLime = лайм .desc = Лечит космическую цингу, позволяет вести себя как космический пират. ent-FoodOrange = апельсин .desc = Полезный, оранжевый. +ent-FoodExtradimensionalOrange = extradimensional orange + .desc = You can hardly wrap your head around this thing. ent-FoodPineapple = ананас .desc = Ммм, тропический. ent-FoodPotato = картофель @@ -123,6 +127,10 @@ ent-FoodWatermelon = арбуз .desc = Круглый зелёный предмет, который можно порезать и съесть. ent-FoodWatermelonSlice = ломтик арбуза .desc = Сочный зелёный и красный ломтик. +ent-FoodHolymelon = holymelon + .desc = The water within this melon has been blessed by some deity that's particularly fond of watermelon. +ent-FoodHolymelonSlice = holymelon slice + .desc = Juicy golden and red slice. ent-FoodGrape = виноград .desc = Пища императоров, жителей космической Франции (обычно в виде вина) и занятых мамочек. Когда-нибудь его можно будет использовать в производстве вина для бармена, если оно вдруг закончится. ent-FoodBerries = ягоды @@ -133,6 +141,8 @@ ent-FoodBungoPit = косточка бунго .desc = { ent-FoodInjectableBase.desc } ent-FoodPeaPod = стручок гороха .desc = Любимое лакомство уток! +ent-FoodWorldPeas = cluster of world peas + .desc = It's rumored to bring peace to any who consume it. ent-FoodPumpkin = тыква .desc = Большой, оранжевый... ягода. Серьёзно. ent-FoodBluePumpkin = синяя тыква diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/devices/encryption_keys.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/devices/encryption_keys.ftl index 3b429c766b0..0a24a0e4837 100644 --- a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/devices/encryption_keys.ftl +++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/devices/encryption_keys.ftl @@ -28,5 +28,7 @@ ent-EncryptionKeySyndie = кроваво-красный ключ шифрова .desc = Ключ шифрования, используемый... секундочку... Кто владелец этого чипа? ent-EncryptionKeyBinary = двоичный ключ шифрования .desc = Ключ шифрования, используемый для преобразования двоичного кода, используемого роботами. +ent-EncryptionKeyBinarySyndicate = binary translator key + .desc = A syndicate encryption key that translates binary signals used by silicons. ent-EncryptionKeyFreelance = ключ шифрования фрилансеров .desc = Ключ шифрования, используемый фрилансерами, которые могут иметь или не иметь отношения к корпорации. Выглядит поношенным. diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/devices/station_beacon.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/devices/station_beacon.ftl index b7cbbb83a00..e3de816088d 100644 --- a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/devices/station_beacon.ftl +++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/devices/station_beacon.ftl @@ -15,6 +15,9 @@ ent-DefaultStationBeaconBridge = { ent-DefaultStationBeaconCommand } ent-DefaultStationBeaconVault = { ent-DefaultStationBeaconCommand } .suffix = Хранилище .desc = { ent-DefaultStationBeaconCommand.desc } +ent-DefaultStationBeaconGateway = { ent-DefaultStationBeaconCommand } + .suffix = Gateway + .desc = { ent-DefaultStationBeaconCommand.desc } ent-DefaultStationBeaconCaptainsQuarters = { ent-DefaultStationBeaconCommand } .suffix = Каюта капитана .desc = { ent-DefaultStationBeaconCommand.desc } diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/fun/immovable_rod.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/fun/immovable_rod.ftl index 7900153701e..d102643fc3b 100644 --- a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/fun/immovable_rod.ftl +++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/fun/immovable_rod.ftl @@ -29,3 +29,5 @@ ent-ImmovableRodThrongler = неподвижный нагибатор .desc = Поймаете - можете оставить себе. ent-ImmovableRodGibstick = неподвижная гиб-палка .desc = А чего вы ожидали? +ent-ImmovableRodWeh = immovable weh + .desc = WEH! diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/fun/toys.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/fun/toys.ftl index ecbaaad4ea9..6b1ec129dfd 100644 --- a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/fun/toys.ftl +++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/fun/toys.ftl @@ -125,3 +125,5 @@ ent-PlushieHuman = плюшевый человек .desc = Плюшевый человек из войлока. Качество - ниже не бывает. Человек голый. Человек плачет. Человек кричит. ent-NewtonCradle = колыбель Ньютона .desc = Устройство, которое скучающие бумагомаратели используют, дабы напомнить себе, что время ещё не остановилось. Содержит гравитацию. +ent-RubberChicken = rubber chicken + .desc = A stress inducing parody of nature's most delectable avian. diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/specific/hydroponics/seeds.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/specific/hydroponics/seeds.ftl index f04928a094b..b038ad76ee9 100644 --- a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/specific/hydroponics/seeds.ftl +++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/specific/hydroponics/seeds.ftl @@ -2,6 +2,8 @@ ent-SeedBase = { ent-BaseItem } .desc = { ent-BaseItem.desc } ent-WheatSeeds = пакет семян (пшеница) .desc = { ent-SeedBase.desc } +ent-MeatwheatSeeds = packet of meatwheat seeds + .desc = If you ever wanted to drive a vegetarian to insanity, here's how. ent-OatSeeds = пакет семян (овёс) .desc = { ent-SeedBase.desc } ent-BananaSeeds = пакет семян (банан) @@ -24,6 +26,8 @@ ent-LimeSeeds = пакет семян (лайм) .desc = { ent-SeedBase.desc } ent-OrangeSeeds = пакет семян (апельсин) .desc = { ent-SeedBase.desc } +ent-ExtradimensionalOrangeSeeds = packet of extradimensional orange seeds + .desc = Polygonal seeds. ent-PineappleSeeds = пакет семян (ананас) .desc = { ent-SeedBase.desc } ent-PotatoSeeds = пакет семян (картофель) @@ -106,6 +110,8 @@ ent-OnionRedSeeds = пакет семян (красный лук) .desc = Несмотря на название, фиолетовый. ent-WatermelonSeeds = пакет семян (арбуз) .desc = { ent-SeedBase.desc } +ent-HolymelonSeeds = packet of holymelon seeds + .desc = { ent-SeedBase.desc } ent-GrapeSeeds = пакет семян (виноград) .desc = { ent-SeedBase.desc } ent-CocoaSeeds = пакет семян (какао-бобы) @@ -116,6 +122,8 @@ ent-BungoSeeds = пакет семян (бунго) .desc = Не ешьте косточки. ent-PeaSeeds = пакет семян (горох) .desc = Когда-то это скромное растение играло важную роль в изучении генетики. +ent-WorldPeaSeeds = packet of world pea seeds + .desc = These rather large seeds give off a soothing blue glow. ent-PumpkinSeeds = пакет семян (тыква) .desc = { ent-SeedBase.desc } ent-BluePumpkinSeeds = пакет семян (синяя тыква) diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/structures/doors/airlocks/access.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/structures/doors/airlocks/access.ftl index 2e43905a27a..89df2700260 100644 --- a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/structures/doors/airlocks/access.ftl +++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/structures/doors/airlocks/access.ftl @@ -190,6 +190,9 @@ ent-AirlockMiningGlassLocked = { ent-AirlockMiningGlass } ent-AirlockChemistryGlassLocked = { ent-AirlockChemistryGlass } .suffix = Химия, Закрыт .desc = { ent-AirlockChemistryGlass.desc } +ent-AirlockMedicalMorgueGlassLocked = { ent-AirlockMedicalGlass } + .suffix = Morgue, Locked + .desc = { ent-AirlockMedicalGlass.desc } ent-AirlockMedicalGlassLocked = { ent-AirlockMedicalGlass } .suffix = Медицинский, Закрыт .desc = { ent-AirlockMedicalGlass.desc } diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/structures/machines/vending_machines.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/structures/machines/vending_machines.ftl index 03d83b723a5..a32eb0c70f9 100644 --- a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/structures/machines/vending_machines.ftl +++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/structures/machines/vending_machines.ftl @@ -6,6 +6,8 @@ ent-VendingMachineAmmo = ПулеМат .desc = То что нужно для массовых убийств. ent-VendingMachineBooze = АлкоМат .desc = Чудо технологической мысли, по замыслу способное смешать именно ту смесь, которую вы хотите выпить, стоит вам только попросить. +ent-VendingMachineBoozeSyndicate = Bruise-O-Mat + .desc = A refurbished Booze-O-Mat for boosting operative morale. An imprint of a blood-red hardsuit is visible on one side, and the paint seems ashed off on the other side. ent-VendingBarDrobe = БарДероб .desc = Стильный автомат для раздачи самой стильной барной униформы! ent-VendingMachineChefvend = Шефвенд diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/structures/specific/anomaly/anomaly_injections.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/structures/specific/anomaly/anomaly_injections.ftl new file mode 100644 index 00000000000..52a8391fade --- /dev/null +++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/structures/specific/anomaly/anomaly_injections.ftl @@ -0,0 +1,22 @@ +ent-AnomalyInjectionBase = { "" } + .desc = { "" } +ent-AnomalyInjectionPyroclastic = { ent-AnomalyInjectionBase } + .desc = { ent-AnomalyInjectionBase.desc } +ent-AnomalyInjectionElectric = { ent-AnomalyInjectionBase } + .desc = { ent-AnomalyInjectionBase.desc } +ent-AnomalyInjectionShadow = { ent-AnomalyInjectionBase } + .desc = { ent-AnomalyInjectionBase.desc } +ent-AnomalyInjectionIce = { ent-AnomalyInjectionBase } + .desc = { ent-AnomalyInjectionBase.desc } +ent-AnomalyInjectionFlora = { ent-AnomalyInjectionBase } + .desc = { ent-AnomalyInjectionBase.desc } +ent-AnomalyInjectionBluespace = { ent-AnomalyInjectionBase } + .desc = { ent-AnomalyInjectionBase.desc } +ent-AnomalyInjectionFlesh = { ent-AnomalyInjectionBase } + .desc = { ent-AnomalyInjectionBase.desc } +ent-AnomalyInjectionGravity = { ent-AnomalyInjectionBase } + .desc = { ent-AnomalyInjectionBase.desc } +ent-AnomalyInjectionTech = { ent-AnomalyInjectionBase } + .desc = { ent-AnomalyInjectionBase.desc } +ent-AnomalyInjectionRock = { ent-AnomalyInjectionBase } + .desc = { ent-AnomalyInjectionBase.desc } diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/structures/specific/anomaly/anomaly_injectors.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/structures/specific/anomaly/anomaly_injectors.ftl new file mode 100644 index 00000000000..b8243e85127 --- /dev/null +++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/structures/specific/anomaly/anomaly_injectors.ftl @@ -0,0 +1,32 @@ +ent-BaseAnomalyInjector = anomaly injector + .desc = { ent-MarkerBase.desc } +ent-AnomalyTrapPyroclastic = { ent-BaseAnomalyInjector } + .suffix = Pyroclastic + .desc = { ent-BaseAnomalyInjector.desc } +ent-AnomalyTrapElectricity = { ent-BaseAnomalyInjector } + .suffix = Electricity + .desc = { ent-BaseAnomalyInjector.desc } +ent-AnomalyTrapShadow = { ent-BaseAnomalyInjector } + .suffix = Shadow + .desc = { ent-BaseAnomalyInjector.desc } +ent-AnomalyTrapIce = { ent-BaseAnomalyInjector } + .suffix = Ice + .desc = { ent-BaseAnomalyInjector.desc } +ent-AnomalyTrapFlora = { ent-BaseAnomalyInjector } + .suffix = Flora + .desc = { ent-BaseAnomalyInjector.desc } +ent-AnomalyTrapBluespace = { ent-BaseAnomalyInjector } + .suffix = Bluespace + .desc = { ent-BaseAnomalyInjector.desc } +ent-AnomalyTrapFlesh = { ent-BaseAnomalyInjector } + .suffix = Flesh + .desc = { ent-BaseAnomalyInjector.desc } +ent-AnomalyTrapGravity = { ent-BaseAnomalyInjector } + .suffix = Gravity + .desc = { ent-BaseAnomalyInjector.desc } +ent-AnomalyTrapTech = { ent-BaseAnomalyInjector } + .suffix = Tech + .desc = { ent-BaseAnomalyInjector.desc } +ent-AnomalyTrapRock = { ent-BaseAnomalyInjector } + .suffix = Rock + .desc = { ent-BaseAnomalyInjector.desc } diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/structures/wallmounts/intercom.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/structures/wallmounts/intercom.ftl index c105388961b..5f91e1b77b8 100644 --- a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/structures/wallmounts/intercom.ftl +++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/structures/wallmounts/intercom.ftl @@ -7,6 +7,8 @@ ent-IntercomConstructed = { ent-BaseIntercom } .desc = { ent-BaseIntercom.desc } ent-Intercom = { ent-IntercomConstructed } .desc = { ent-IntercomConstructed.desc } +ent-BaseIntercomSecure = { ent-Intercom } + .desc = { ent-Intercom.desc } ent-IntercomCommon = { ent-Intercom } .suffix = Общий .desc = { ent-Intercom.desc } diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/gamerules/events.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/gamerules/events.ftl index 2affaa913be..f383f1ba5db 100644 --- a/Resources/Locale/ru-RU/ss14-ru/prototypes/gamerules/events.ftl +++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/gamerules/events.ftl @@ -36,6 +36,8 @@ ent-VentClog = { ent-BaseStationEventLongDelay } .desc = { ent-BaseStationEventLongDelay.desc } ent-SlimesSpawn = { ent-BaseStationEventShortDelay } .desc = { ent-BaseStationEventShortDelay.desc } +ent-SnakeSpawn = { ent-BaseStationEventShortDelay } + .desc = { ent-BaseStationEventShortDelay.desc } ent-SpiderSpawn = { ent-BaseStationEventShortDelay } .desc = { ent-BaseStationEventShortDelay.desc } ent-SpiderClownSpawn = { ent-BaseStationEventShortDelay } diff --git a/Resources/Locale/ru-RU/station-events/events/ion-storm.ftl b/Resources/Locale/ru-RU/station-events/events/ion-storm.ftl index 683a0eef4b4..947f808e57f 100644 --- a/Resources/Locale/ru-RU/station-events/events/ion-storm.ftl +++ b/Resources/Locale/ru-RU/station-events/events/ion-storm.ftl @@ -7,6 +7,7 @@ ion-storm-the-job = { CAPITALIZE($job) } ion-storm-clowns = КЛОУНЫ ion-storm-heads = ГЛАВЫ ОТДЕЛОВ ion-storm-crew = ЭКИПАЖ +ion-storm-people = PEOPLE ion-storm-adjective-things = { $adjective } ОБЪЕКТЫ ion-storm-x-and-y = { $x } И { $y } # joined is short for {$number} {$adjective} diff --git a/Resources/Locale/ru-RU/traits/traits.ftl b/Resources/Locale/ru-RU/traits/traits.ftl index 00c5a9d8f9e..c0200689bc4 100644 --- a/Resources/Locale/ru-RU/traits/traits.ftl +++ b/Resources/Locale/ru-RU/traits/traits.ftl @@ -35,3 +35,7 @@ trait-german-name = Немецкий акцент trait-german-desc = Вы, кажется, родом из Космической Германии. trait-italian-name = Итальянский акцент trait-italian-desc = Мамма миа! Похоже, вы жили в Космической Италии! +trait-french-name = French accent +trait-french-desc = Your accent seems to have a certain «je ne sais quoi». +trait-spanish-name = Spanish accent +trait-spanish-desc = Hola señor, donde esta la biblioteca. diff --git a/Resources/Locale/ru-RU/wires/components/wires-component.ftl b/Resources/Locale/ru-RU/wires/components/wires-component.ftl index 654a5abf685..1b9fa04e75c 100644 --- a/Resources/Locale/ru-RU/wires/components/wires-component.ftl +++ b/Resources/Locale/ru-RU/wires/components/wires-component.ftl @@ -10,3 +10,9 @@ wires-component-ui-on-receive-message-cannot-mend-uncut-wire = Вы не мож wires-menu-name-label = Провода wires-menu-dead-beef-text = DEAD-BEEF +wires-menu-help-popup = + Click on the gold contacts with a multitool in hand to pulse their wire. + Click on the wires with a pair of wirecutters in hand to cut/mend them. + + The lights at the top show the state of the machine, messing with wires will probably do stuff to them. + Wire layouts are different each round, but consistent between machines of the same type. From 71c08d632234d68cb129b141f66031f7204a16fa Mon Sep 17 00:00:00 2001 From: Morb0 <14136326+Morb0@users.noreply.github.com> Date: Thu, 19 Sep 2024 11:05:31 +0300 Subject: [PATCH 137/138] Remove old data (???) --- .../prototypes/corvax/objectives/eviltwin.ftl | 4 --- .../Prototypes/Corvax/Objectives/eviltwin.yml | 26 ------------------- 2 files changed, 30 deletions(-) delete mode 100644 Resources/Locale/ru-RU/ss14-ru/prototypes/corvax/objectives/eviltwin.ftl delete mode 100644 Resources/Prototypes/Corvax/Objectives/eviltwin.yml diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/corvax/objectives/eviltwin.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/corvax/objectives/eviltwin.ftl deleted file mode 100644 index 28bb39af426..00000000000 --- a/Resources/Locale/ru-RU/ss14-ru/prototypes/corvax/objectives/eviltwin.ftl +++ /dev/null @@ -1,4 +0,0 @@ -ent-EscapeShuttleTwinObjective = Улететь на Центком живым и свободным. - .desc = Продолжите своё тайное внедрение на Центкоме. -ent-KillTwinObjective = Убить оригинал. - .desc = Убейте свой оригинал и займите его место. diff --git a/Resources/Prototypes/Corvax/Objectives/eviltwin.yml b/Resources/Prototypes/Corvax/Objectives/eviltwin.yml deleted file mode 100644 index b9cd12c450e..00000000000 --- a/Resources/Prototypes/Corvax/Objectives/eviltwin.yml +++ /dev/null @@ -1,26 +0,0 @@ -- type: entity - noSpawn: true - parent: [BaseTraitorObjective, BaseLivingObjective] - id: EscapeShuttleTwinObjective - name: Escape to centcom alive and unrestrained. - description: Continue your covert implementation already on Centcom. - components: - - type: Objective - difficulty: 1.3 - icon: - sprite: Structures/Furniture/chairs.rsi - state: shuttle - - type: EscapeShuttleCondition - -- type: entity - noSpawn: true - parent: [BaseTraitorObjective, BaseKillObjective] - id: KillTwinObjective - name: Kill original persona. - description: Kill your original persona and take his place. - components: - - type: Objective - difficulty: 1.75 - unique: false - - type: TargetObjective - title: objective-condition-kill-person-title From 768b5e9862a8b2e8bbee7950260a7d7f5eaf3711 Mon Sep 17 00:00:00 2001 From: Morb0 <14136326+Morb0@users.noreply.github.com> Date: Thu, 19 Sep 2024 11:05:49 +0300 Subject: [PATCH 138/138] Use categories for hide spawn menu --- Resources/Prototypes/Corvax/Body/Organs/vulpkanin.yml | 2 +- .../Corvax/Entities/Clothing/Head/hardsuit-helmets.yml | 2 +- .../Entities/Markers/Spawners/Random/framestationrandom.yml | 2 +- .../Prototypes/Corvax/Entities/Mobs/Species/vulpkanin.yml | 2 +- Resources/Prototypes/Corvax/Entities/Stations/nanotrasen.yml | 2 +- Resources/Prototypes/Corvax/Objectives/traitorObjectives.yml | 4 +--- Resources/Prototypes/Objectives/traitor.yml | 3 +-- 7 files changed, 7 insertions(+), 10 deletions(-) diff --git a/Resources/Prototypes/Corvax/Body/Organs/vulpkanin.yml b/Resources/Prototypes/Corvax/Body/Organs/vulpkanin.yml index 90eb4e6deaa..f1e64d5d839 100644 --- a/Resources/Prototypes/Corvax/Body/Organs/vulpkanin.yml +++ b/Resources/Prototypes/Corvax/Body/Organs/vulpkanin.yml @@ -1,7 +1,7 @@ - type: entity id: OrganVulpkaninStomach parent: OrganAnimalStomach - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Stomach - type: SolutionContainerManager diff --git a/Resources/Prototypes/Corvax/Entities/Clothing/Head/hardsuit-helmets.yml b/Resources/Prototypes/Corvax/Entities/Clothing/Head/hardsuit-helmets.yml index b95e950a1b8..dd3b7ecd60c 100644 --- a/Resources/Prototypes/Corvax/Entities/Clothing/Head/hardsuit-helmets.yml +++ b/Resources/Prototypes/Corvax/Entities/Clothing/Head/hardsuit-helmets.yml @@ -1,7 +1,7 @@ - type: entity parent: ClothingHeadHardsuitWithLightBase id: ClothingHeadHelmetCBURNLeader - noSpawn: true + categories: [ HideSpawnMenu ] name: cburn commander helmet description: A pressure resistant and fireproof hood worn by special cleanup units. components: diff --git a/Resources/Prototypes/Corvax/Entities/Markers/Spawners/Random/framestationrandom.yml b/Resources/Prototypes/Corvax/Entities/Markers/Spawners/Random/framestationrandom.yml index f52d7194337..299da5963c9 100644 --- a/Resources/Prototypes/Corvax/Entities/Markers/Spawners/Random/framestationrandom.yml +++ b/Resources/Prototypes/Corvax/Entities/Markers/Spawners/Random/framestationrandom.yml @@ -1,7 +1,7 @@ - type: entity id: FrameStationRandomSpawner parent: MarkerBase - noSpawn: true # Used only for CorvaxFrame + categories: [ HideSpawnMenu, Spawner ] # Used only for CorvaxFrame components: - type: RandomSpawner rarePrototypes: diff --git a/Resources/Prototypes/Corvax/Entities/Mobs/Species/vulpkanin.yml b/Resources/Prototypes/Corvax/Entities/Mobs/Species/vulpkanin.yml index 5f81271b4c1..6d6e2ef06f1 100644 --- a/Resources/Prototypes/Corvax/Entities/Mobs/Species/vulpkanin.yml +++ b/Resources/Prototypes/Corvax/Entities/Mobs/Species/vulpkanin.yml @@ -66,7 +66,7 @@ name: Urist McHands parent: MobHumanDummy id: MobVulpkaninDummy - noSpawn: true + categories: [ HideSpawnMenu ] description: A dummy vulpkanin meant to be used in character setup. components: - type: HumanoidAppearance diff --git a/Resources/Prototypes/Corvax/Entities/Stations/nanotrasen.yml b/Resources/Prototypes/Corvax/Entities/Stations/nanotrasen.yml index f087f2d5856..550fc2c5bd5 100644 --- a/Resources/Prototypes/Corvax/Entities/Stations/nanotrasen.yml +++ b/Resources/Prototypes/Corvax/Entities/Stations/nanotrasen.yml @@ -17,7 +17,7 @@ - BaseStationSiliconLawCrewsimov - BaseStationAllEventsEligible - BaseStationNanotrasen - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Transform - type: GridSpawn diff --git a/Resources/Prototypes/Corvax/Objectives/traitorObjectives.yml b/Resources/Prototypes/Corvax/Objectives/traitorObjectives.yml index a619e7b6d01..54ac0a1c229 100644 --- a/Resources/Prototypes/Corvax/Objectives/traitorObjectives.yml +++ b/Resources/Prototypes/Corvax/Objectives/traitorObjectives.yml @@ -1,5 +1,4 @@ - type: entity - noSpawn: true parent: [BaseTraitorObjective, BaseLivingObjective] id: HijackShuttleObjective name: Hijack emergency shuttle @@ -13,7 +12,6 @@ - type: HijackShuttleCondition - type: entity - noSpawn: true parent: BaseCaptainObjective id: NukeDiskStealObjective components: @@ -36,4 +34,4 @@ - type: NotCommandRequirement - type: StealCondition stealGroup: NukeDisk - owner: objective-condition-steal-station \ No newline at end of file + owner: objective-condition-steal-station diff --git a/Resources/Prototypes/Objectives/traitor.yml b/Resources/Prototypes/Objectives/traitor.yml index a5381c75aa1..b126a16c220 100644 --- a/Resources/Prototypes/Objectives/traitor.yml +++ b/Resources/Prototypes/Objectives/traitor.yml @@ -282,7 +282,6 @@ # Corvax-MRP-Start: Make nuke disk objective separate # - type: entity - # noSpawn: true # parent: BaseCaptainObjective # id: NukeDiskStealObjective # components: @@ -295,4 +294,4 @@ # - type: StealCondition # stealGroup: NukeDisk # owner: objective-condition-steal-station -# Corvax-MRP-End \ No newline at end of file +# Corvax-MRP-End