diff --git a/Content.Client/Flight/Components/FlightVisualsComponent.cs b/Content.Client/Flight/Components/FlightVisualsComponent.cs
new file mode 100644
index 0000000000..3f378f60ef
--- /dev/null
+++ b/Content.Client/Flight/Components/FlightVisualsComponent.cs
@@ -0,0 +1,40 @@
+using Robust.Client.Graphics;
+using Robust.Shared.GameStates;
+
+namespace Content.Client.Flight.Components;
+
+[RegisterComponent]
+public sealed partial class FlightVisualsComponent : Component
+{
+ ///
+ /// How long does the animation last
+ ///
+ [DataField]
+ public float Speed;
+
+ ///
+ /// How far it goes in any direction.
+ ///
+ [DataField]
+ public float Multiplier;
+
+ ///
+ /// How much the limbs (if there are any) rotate.
+ ///
+ [DataField]
+ public float Offset;
+
+ ///
+ /// Are we animating layers or the entire sprite?
+ ///
+ public bool AnimateLayer = false;
+ public int? TargetLayer;
+
+ [DataField]
+ public string AnimationKey = "default";
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ public ShaderInstance Shader = default!;
+
+
+}
\ No newline at end of file
diff --git a/Content.Client/Flight/FlightSystem.cs b/Content.Client/Flight/FlightSystem.cs
new file mode 100644
index 0000000000..bd1a6767bd
--- /dev/null
+++ b/Content.Client/Flight/FlightSystem.cs
@@ -0,0 +1,67 @@
+using Robust.Client.GameObjects;
+using Content.Shared.Flight;
+using Content.Shared.Flight.Events;
+using Content.Client.Flight.Components;
+
+namespace Content.Client.Flight;
+public sealed class FlightSystem : SharedFlightSystem
+{
+ [Dependency] private readonly IEntityManager _entityManager = default!;
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeNetworkEvent(OnFlight);
+
+ }
+
+ private void OnFlight(FlightEvent args)
+ {
+ var uid = GetEntity(args.Uid);
+ if (!_entityManager.TryGetComponent(uid, out SpriteComponent? sprite)
+ || !args.IsAnimated
+ || !_entityManager.TryGetComponent(uid, out FlightComponent? flight))
+ return;
+
+
+ int? targetLayer = null;
+ if (flight.IsLayerAnimated && flight.Layer is not null)
+ {
+ targetLayer = GetAnimatedLayer(uid, flight.Layer, sprite);
+ if (targetLayer == null)
+ return;
+ }
+
+ if (args.IsFlying && args.IsAnimated && flight.AnimationKey != "default")
+ {
+ var comp = new FlightVisualsComponent
+ {
+ AnimateLayer = flight.IsLayerAnimated,
+ AnimationKey = flight.AnimationKey,
+ Multiplier = flight.ShaderMultiplier,
+ Offset = flight.ShaderOffset,
+ Speed = flight.ShaderSpeed,
+ TargetLayer = targetLayer,
+ };
+ AddComp(uid, comp);
+ }
+ if (!args.IsFlying)
+ RemComp(uid);
+ }
+
+ public int? GetAnimatedLayer(EntityUid uid, string targetLayer, SpriteComponent? sprite = null)
+ {
+ if (!Resolve(uid, ref sprite))
+ return null;
+
+ int index = 0;
+ foreach (var layer in sprite.AllLayers)
+ {
+ // This feels like absolute shitcode, isn't there a better way to check for it?
+ if (layer.Rsi?.Path.ToString() == targetLayer)
+ return index;
+ index++;
+ }
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/Content.Client/Flight/FlyingVisualizerSystem.cs b/Content.Client/Flight/FlyingVisualizerSystem.cs
new file mode 100644
index 0000000000..6dde6cf563
--- /dev/null
+++ b/Content.Client/Flight/FlyingVisualizerSystem.cs
@@ -0,0 +1,64 @@
+using Content.Client.Flight.Components;
+using Robust.Client.GameObjects;
+using Robust.Client.Graphics;
+using Robust.Shared.Prototypes;
+
+namespace Content.Client.Flight;
+
+///
+/// Handles offsetting an entity while flying
+///
+public sealed class FlyingVisualizerSystem : EntitySystem
+{
+ [Dependency] private readonly IPrototypeManager _protoMan = default!;
+ [Dependency] private readonly SpriteSystem _spriteSystem = default!;
+ public override void Initialize()
+ {
+ base.Initialize();
+ SubscribeLocalEvent(OnStartup);
+ SubscribeLocalEvent(OnShutdown);
+ SubscribeLocalEvent(OnBeforeShaderPost);
+ }
+
+ private void OnStartup(EntityUid uid, FlightVisualsComponent comp, ComponentStartup args)
+ {
+ comp.Shader = _protoMan.Index(comp.AnimationKey).InstanceUnique();
+ AddShader(uid, comp.Shader, comp.AnimateLayer, comp.TargetLayer);
+ SetValues(comp, comp.Speed, comp.Offset, comp.Multiplier);
+ }
+
+ private void OnShutdown(EntityUid uid, FlightVisualsComponent comp, ComponentShutdown args)
+ {
+ AddShader(uid, null, comp.AnimateLayer, comp.TargetLayer);
+ }
+
+ private void AddShader(Entity entity, ShaderInstance? shader, bool animateLayer, int? layer)
+ {
+ if (!Resolve(entity, ref entity.Comp, false))
+ return;
+
+ if (!animateLayer)
+ entity.Comp.PostShader = shader;
+
+ if (animateLayer && layer is not null)
+ entity.Comp.LayerSetShader(layer.Value, shader);
+
+ entity.Comp.GetScreenTexture = shader is not null;
+ entity.Comp.RaiseShaderEvent = shader is not null;
+ }
+
+ ///
+ /// This function can be used to modify the shader's values while its running.
+ ///
+ private void OnBeforeShaderPost(EntityUid uid, FlightVisualsComponent comp, ref BeforePostShaderRenderEvent args)
+ {
+ SetValues(comp, comp.Speed, comp.Offset, comp.Multiplier);
+ }
+
+ private void SetValues(FlightVisualsComponent comp, float speed, float offset, float multiplier)
+ {
+ comp.Shader.SetParameter("Speed", speed);
+ comp.Shader.SetParameter("Offset", offset);
+ comp.Shader.SetParameter("Multiplier", multiplier);
+ }
+}
\ No newline at end of file
diff --git a/Content.Client/Guidebook/Controls/GuideFoodComposition.xaml b/Content.Client/Guidebook/Controls/GuideFoodComposition.xaml
new file mode 100644
index 0000000000..6a3072ce08
--- /dev/null
+++ b/Content.Client/Guidebook/Controls/GuideFoodComposition.xaml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
diff --git a/Content.Client/Guidebook/Controls/GuideFoodComposition.xaml.cs b/Content.Client/Guidebook/Controls/GuideFoodComposition.xaml.cs
new file mode 100644
index 0000000000..b4f25a02e4
--- /dev/null
+++ b/Content.Client/Guidebook/Controls/GuideFoodComposition.xaml.cs
@@ -0,0 +1,31 @@
+using Content.Client.UserInterface.ControlExtensions;
+using Content.Shared.Chemistry.Reagent;
+using Content.Shared.FixedPoint;
+using JetBrains.Annotations;
+using Robust.Client.AutoGenerated;
+using Robust.Client.UserInterface.Controls;
+using Robust.Client.UserInterface.XAML;
+
+namespace Content.Client.Guidebook.Controls;
+
+[UsedImplicitly, GenerateTypedNameReferences]
+public sealed partial class GuideFoodComposition : BoxContainer, ISearchableControl
+{
+ public GuideFoodComposition(ReagentPrototype proto, FixedPoint2 quantity)
+ {
+ RobustXamlLoader.Load(this);
+
+ ReagentLabel.Text = proto.LocalizedName;
+ AmountLabel.Text = quantity.ToString();
+ }
+
+ public bool CheckMatchesSearch(string query)
+ {
+ return this.ChildrenContainText(query);
+ }
+
+ public void SetHiddenState(bool state, string query)
+ {
+ Visible = CheckMatchesSearch(query) ? state : !state;
+ }
+}
diff --git a/Content.Client/Guidebook/Controls/GuideFoodEmbed.xaml b/Content.Client/Guidebook/Controls/GuideFoodEmbed.xaml
new file mode 100644
index 0000000000..8aa2b10356
--- /dev/null
+++ b/Content.Client/Guidebook/Controls/GuideFoodEmbed.xaml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Content.Client/Guidebook/Controls/GuideFoodEmbed.xaml.cs b/Content.Client/Guidebook/Controls/GuideFoodEmbed.xaml.cs
new file mode 100644
index 0000000000..355d3a020f
--- /dev/null
+++ b/Content.Client/Guidebook/Controls/GuideFoodEmbed.xaml.cs
@@ -0,0 +1,161 @@
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using Content.Client.Chemistry.EntitySystems;
+using Content.Client.Guidebook.Richtext;
+using Content.Client.Message;
+using Content.Client.Nutrition.EntitySystems;
+using Content.Shared.Chemistry.Reagent;
+using Content.Shared.FixedPoint;
+using JetBrains.Annotations;
+using Robust.Client.AutoGenerated;
+using Robust.Client.Graphics;
+using Robust.Client.UserInterface;
+using Robust.Client.UserInterface.Controls;
+using Robust.Client.UserInterface.XAML;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Utility;
+
+namespace Content.Client.Guidebook.Controls;
+
+///
+/// Control for embedding a food recipe into a guidebook.
+///
+[UsedImplicitly, GenerateTypedNameReferences]
+public sealed partial class GuideFoodEmbed : BoxContainer, IDocumentTag, ISearchableControl
+{
+ [Dependency] private readonly IEntitySystemManager _systemManager = default!;
+ [Dependency] private readonly IPrototypeManager _prototype = default!;
+
+ private readonly FoodGuideDataSystem _foodGuideData;
+ private readonly ISawmill _logger = default!;
+
+ public GuideFoodEmbed()
+ {
+ RobustXamlLoader.Load(this);
+ IoCManager.InjectDependencies(this);
+ _foodGuideData = _systemManager.GetEntitySystem();
+ _logger = Logger.GetSawmill("food guide");
+ MouseFilter = MouseFilterMode.Stop;
+ }
+
+ public GuideFoodEmbed(FoodGuideEntry entry) : this()
+ {
+ GenerateControl(entry);
+ }
+
+ public bool CheckMatchesSearch(string query)
+ {
+ return FoodName.GetMessage()?.Contains(query, StringComparison.InvariantCultureIgnoreCase) == true
+ || FoodDescription.GetMessage()?.Contains(query, StringComparison.InvariantCultureIgnoreCase) == true;
+ }
+
+ public void SetHiddenState(bool state, string query)
+ {
+ Visible = CheckMatchesSearch(query) ? state : !state;
+ }
+
+ public bool TryParseTag(Dictionary args, [NotNullWhen(true)] out Control? control)
+ {
+ control = null;
+ if (!args.TryGetValue("Food", out var id))
+ {
+ _logger.Error("Food embed tag is missing food prototype argument.");
+ return false;
+ }
+
+ if (!_foodGuideData.TryGetData(id, out var data))
+ {
+ _logger.Warning($"Specified food prototype \"{id}\" does not have any known sources.");
+ return false;
+ }
+
+ GenerateControl(data);
+
+ control = this;
+ return true;
+ }
+
+ private void GenerateControl(FoodGuideEntry data)
+ {
+ _prototype.TryIndex(data.Result, out var proto);
+ if (proto == null)
+ {
+ FoodName.SetMarkup(Loc.GetString("guidebook-food-unknown-proto", ("id", data.Result)));
+ return;
+ }
+
+ var composition = data.Composition
+ .Select(it => _prototype.TryIndex(it.Reagent.Prototype, out var reagent) ? (reagent, it.Quantity) : (null, 0))
+ .Where(it => it.reagent is not null)
+ .Cast<(ReagentPrototype, FixedPoint2)>()
+ .ToList();
+
+ #region Colors
+
+ CalculateColors(composition, out var textColor, out var backgroundColor);
+
+ NameBackground.PanelOverride = new StyleBoxFlat
+ {
+ BackgroundColor = backgroundColor
+ };
+ FoodName.SetMarkup(Loc.GetString("guidebook-food-name", ("color", textColor), ("name", proto.Name)));
+
+ #endregion
+
+ #region Sources
+
+ foreach (var source in data.Sources.OrderBy(it => it.OutputCount))
+ {
+ var control = new GuideFoodSource(proto, source, _prototype);
+ SourcesDescriptionContainer.AddChild(control);
+ }
+
+ #endregion
+
+ #region Composition
+
+ foreach (var (reagent, quantity) in composition)
+ {
+ var control = new GuideFoodComposition(reagent, quantity);
+ CompositionDescriptionContainer.AddChild(control);
+ }
+
+ #endregion
+
+ FormattedMessage description = new();
+ description.AddText(proto?.Description ?? string.Empty);
+ // Cannot describe food flavor or smth beause food is entirely server-side
+
+ FoodDescription.SetMessage(description);
+ }
+
+ private void CalculateColors(List<(ReagentPrototype, FixedPoint2)> composition, out Color text, out Color background)
+ {
+ // Background color is calculated as the weighted average of the colors of the composition.
+ // Text color is determined based on background luminosity.
+ float r = 0, g = 0, b = 0;
+ FixedPoint2 weight = 0;
+
+ foreach (var (proto, quantity) in composition)
+ {
+ var tcolor = proto.SubstanceColor;
+ var prevalence =
+ quantity <= 0 ? 0f
+ : weight == 0f ? 1f
+ : (quantity / (weight + quantity)).Float();
+
+ r = r * (1 - prevalence) + tcolor.R * prevalence;
+ g = g * (1 - prevalence) + tcolor.G * prevalence;
+ b = b * (1 - prevalence) + tcolor.B * prevalence;
+
+ if (quantity > 0)
+ weight += quantity;
+ }
+
+ // Copied from GuideReagentEmbed which was probably copied from stackoverflow. This is the formula for color luminosity.
+ var lum = 0.2126f * r + 0.7152f * g + 0.0722f;
+
+ background = new Color(r, g, b);
+ text = lum > 0.5f ? Color.Black : Color.White;
+ }
+}
diff --git a/Content.Client/Guidebook/Controls/GuideFoodGroupEmbed.xaml b/Content.Client/Guidebook/Controls/GuideFoodGroupEmbed.xaml
new file mode 100644
index 0000000000..da671adaa7
--- /dev/null
+++ b/Content.Client/Guidebook/Controls/GuideFoodGroupEmbed.xaml
@@ -0,0 +1,4 @@
+
+
+
diff --git a/Content.Client/Guidebook/Controls/GuideFoodGroupEmbed.xaml.cs b/Content.Client/Guidebook/Controls/GuideFoodGroupEmbed.xaml.cs
new file mode 100644
index 0000000000..0e1034e394
--- /dev/null
+++ b/Content.Client/Guidebook/Controls/GuideFoodGroupEmbed.xaml.cs
@@ -0,0 +1,38 @@
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using Content.Client.Guidebook.Richtext;
+using Content.Client.Nutrition.EntitySystems;
+using JetBrains.Annotations;
+using Robust.Client.AutoGenerated;
+using Robust.Client.UserInterface;
+using Robust.Client.UserInterface.Controls;
+using Robust.Client.UserInterface.XAML;
+using Robust.Shared.Prototypes;
+
+namespace Content.Client.Guidebook.Controls;
+
+[UsedImplicitly, GenerateTypedNameReferences]
+public sealed partial class GuideFoodGroupEmbed : BoxContainer, IDocumentTag
+{
+ [Dependency] private readonly IEntitySystemManager _sysMan = default!;
+ [Dependency] private readonly IPrototypeManager _prototype = default!;
+
+ public GuideFoodGroupEmbed()
+ {
+ RobustXamlLoader.Load(this);
+ IoCManager.InjectDependencies(this);
+ MouseFilter = MouseFilterMode.Stop;
+
+ foreach (var data in _sysMan.GetEntitySystem().Registry.OrderBy(it => it.Identifier))
+ {
+ var embed = new GuideFoodEmbed(data);
+ GroupContainer.AddChild(embed);
+ }
+ }
+
+ public bool TryParseTag(Dictionary args, [NotNullWhen(true)] out Control? control)
+ {
+ control = this;
+ return true;
+ }
+}
diff --git a/Content.Client/Guidebook/Controls/GuideFoodSource.xaml b/Content.Client/Guidebook/Controls/GuideFoodSource.xaml
new file mode 100644
index 0000000000..74e3a2ec30
--- /dev/null
+++ b/Content.Client/Guidebook/Controls/GuideFoodSource.xaml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Content.Client/Guidebook/Controls/GuideFoodSource.xaml.cs b/Content.Client/Guidebook/Controls/GuideFoodSource.xaml.cs
new file mode 100644
index 0000000000..b0fee70975
--- /dev/null
+++ b/Content.Client/Guidebook/Controls/GuideFoodSource.xaml.cs
@@ -0,0 +1,160 @@
+using System.Linq;
+using Content.Client.Chemistry.EntitySystems;
+using Content.Client.UserInterface.ControlExtensions;
+using Content.Shared.Chemistry.Reagent;
+using Content.Shared.FixedPoint;
+using Content.Shared.Nutrition.Components;
+using JetBrains.Annotations;
+using Robust.Client.AutoGenerated;
+using Robust.Client.GameObjects;
+using Robust.Client.Graphics;
+using Robust.Client.UserInterface.Controls;
+using Robust.Client.UserInterface.XAML;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Utility;
+
+namespace Content.Client.Guidebook.Controls;
+
+[UsedImplicitly, GenerateTypedNameReferences]
+public sealed partial class GuideFoodSource : BoxContainer, ISearchableControl
+{
+ private readonly IPrototypeManager _protoMan;
+ private readonly SpriteSystem _sprites = default!;
+
+ public GuideFoodSource(IPrototypeManager protoMan)
+ {
+ RobustXamlLoader.Load(this);
+ _protoMan = protoMan;
+ _sprites = IoCManager.Resolve().GetEntitySystem();
+ }
+
+ public GuideFoodSource(EntityPrototype result, FoodSourceData entry, IPrototypeManager protoMan) : this(protoMan)
+ {
+ switch (entry)
+ {
+ case FoodButcheringData butchering:
+ GenerateControl(butchering);
+ break;
+ case FoodSlicingData slicing:
+ GenerateControl(slicing);
+ break;
+ case FoodRecipeData recipe:
+ GenerateControl(recipe);
+ break;
+ case FoodReactionData reaction:
+ GenerateControl(reaction);
+ break;
+ default:
+ throw new ArgumentOutOfRangeException(nameof(entry), entry, null);
+ }
+
+ GenerateOutputs(result, entry);
+ }
+
+ private void GenerateControl(FoodButcheringData entry)
+ {
+ if (!_protoMan.TryIndex(entry.Butchered, out var ent))
+ {
+ SourceLabel.SetMessage(Loc.GetString("guidebook-food-unknown-proto", ("id", entry.Butchered)));
+ return;
+ }
+
+ SetSource(ent);
+ ProcessingLabel.Text = Loc.GetString("guidebook-food-processing-butchering");
+
+ ProcessingTexture.Texture = entry.Type switch
+ {
+ ButcheringType.Knife => GetRsiTexture("/Textures/Objects/Weapons/Melee/kitchen_knife.rsi", "icon"),
+ _ => GetRsiTexture("/Textures/Structures/meat_spike.rsi", "spike")
+ };
+ }
+
+ private void GenerateControl(FoodSlicingData entry)
+ {
+ if (!_protoMan.TryIndex(entry.Sliced, out var ent))
+ {
+ SourceLabel.SetMessage(Loc.GetString("guidebook-food-unknown-proto", ("id", entry.Sliced)));
+ return;
+ }
+
+ SetSource(ent);
+ ProcessingLabel.Text = Loc.GetString("guidebook-food-processing-slicing");
+ ProcessingTexture.Texture = GetRsiTexture("/Textures/Objects/Misc/utensils.rsi", "plastic_knife");
+ }
+
+ private void GenerateControl(FoodRecipeData entry)
+ {
+ if (!_protoMan.TryIndex(entry.Recipe, out var recipe))
+ {
+ SourceLabel.SetMessage(Loc.GetString("guidebook-food-unknown-proto", ("id", entry.Result)));
+ return;
+ }
+
+ var combinedSolids = recipe.IngredientsSolids
+ .Select(it => _protoMan.TryIndex(it.Key, out var proto) ? FormatIngredient(proto, it.Value) : "")
+ .Where(it => it.Length > 0);
+ var combinedLiquids = recipe.IngredientsReagents
+ .Select(it => _protoMan.TryIndex(it.Key, out var proto) ? FormatIngredient(proto, it.Value) : "")
+ .Where(it => it.Length > 0);
+
+ var combinedIngredients = string.Join("\n", combinedLiquids.Union(combinedSolids));
+ SourceLabel.SetMessage(Loc.GetString("guidebook-food-processing-recipe", ("ingredients", combinedIngredients)));
+
+ ProcessingTexture.Texture = GetRsiTexture("/Textures/Structures/Machines/microwave.rsi", "mw");
+ ProcessingLabel.Text = Loc.GetString("guidebook-food-processing-cooking", ("time", recipe.CookTime));
+ }
+
+ private void GenerateControl(FoodReactionData entry)
+ {
+ if (!_protoMan.TryIndex(entry.Reaction, out var reaction))
+ {
+ SourceLabel.SetMessage(Loc.GetString("guidebook-food-unknown-proto", ("id", entry.Reaction)));
+ return;
+ }
+
+ var combinedReagents = reaction.Reactants
+ .Select(it => _protoMan.TryIndex(it.Key, out var proto) ? FormatIngredient(proto, it.Value.Amount) : "")
+ .Where(it => it.Length > 0);
+
+ SourceLabel.SetMessage(Loc.GetString("guidebook-food-processing-recipe", ("ingredients", string.Join("\n", combinedReagents))));
+ ProcessingTexture.TexturePath = "/Textures/Interface/Misc/beakerlarge.png";
+ ProcessingLabel.Text = Loc.GetString("guidebook-food-processing-reaction");
+ }
+
+ private Texture GetRsiTexture(string path, string state)
+ {
+ return _sprites.Frame0(new SpriteSpecifier.Rsi(new ResPath(path), state));
+ }
+
+ private void GenerateOutputs(EntityPrototype result, FoodSourceData entry)
+ {
+ OutputsLabel.Text = Loc.GetString("guidebook-food-output", ("name", result.Name), ("number", entry.OutputCount));
+ OutputsTexture.Texture = _sprites.Frame0(result);
+ }
+
+ private void SetSource(EntityPrototype ent)
+ {
+ SourceLabel.SetMessage(ent.Name);
+ OutputsTexture.Texture = _sprites.Frame0(ent);
+ }
+
+ private string FormatIngredient(EntityPrototype proto, FixedPoint2 amount)
+ {
+ return Loc.GetString("guidebook-food-ingredient-solid", ("name", proto.Name), ("amount", amount));
+ }
+
+ private string FormatIngredient(ReagentPrototype proto, FixedPoint2 amount)
+ {
+ return Loc.GetString("guidebook-food-ingredient-liquid", ("name", proto.LocalizedName), ("amount", amount));
+ }
+
+ public bool CheckMatchesSearch(string query)
+ {
+ return this.ChildrenContainText(query);
+ }
+
+ public void SetHiddenState(bool state, string query)
+ {
+ Visible = CheckMatchesSearch(query) ? state : !state;
+ }
+}
diff --git a/Content.Client/Language/LanguageMenuWindow.xaml.cs b/Content.Client/Language/LanguageMenuWindow.xaml.cs
index 11d1c290d1..ed6ec6b3e2 100644
--- a/Content.Client/Language/LanguageMenuWindow.xaml.cs
+++ b/Content.Client/Language/LanguageMenuWindow.xaml.cs
@@ -1,4 +1,5 @@
using Content.Client.Language.Systems;
+using Content.Shared.Language.Events;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
@@ -7,7 +8,7 @@
namespace Content.Client.Language;
[GenerateTypedNameReferences]
-public sealed partial class LanguageMenuWindow : DefaultWindow
+public sealed partial class LanguageMenuWindow : DefaultWindow, IEntityEventSubscriber
{
private readonly LanguageSystem _clientLanguageSystem;
private readonly List _entries = new();
@@ -17,6 +18,14 @@ public LanguageMenuWindow()
{
RobustXamlLoader.Load(this);
_clientLanguageSystem = IoCManager.Resolve().GetEntitySystem();
+
+ _clientLanguageSystem.OnLanguagesChanged += OnUpdateState;
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ base.Dispose(disposing);
+ _clientLanguageSystem.OnLanguagesChanged -= OnUpdateState;
}
protected override void Opened()
@@ -28,6 +37,11 @@ protected override void Opened()
}
+ private void OnUpdateState(object? sender, LanguagesUpdatedMessage args)
+ {
+ UpdateState(args.CurrentLanguage, args.Spoken);
+ }
+
public void UpdateState(string currentLanguage, List spokenLanguages)
{
var langName = Loc.GetString($"language-{currentLanguage}-name");
diff --git a/Content.Client/Language/Systems/LanguageSystem.cs b/Content.Client/Language/Systems/LanguageSystem.cs
index 5dc2fc1f4e..cb6bb60512 100644
--- a/Content.Client/Language/Systems/LanguageSystem.cs
+++ b/Content.Client/Language/Systems/LanguageSystem.cs
@@ -29,6 +29,8 @@ public sealed class LanguageSystem : SharedLanguageSystem
///
public List UnderstoodLanguages { get; private set; } = new();
+ public event EventHandler? OnLanguagesChanged;
+
public override void Initialize()
{
base.Initialize();
@@ -39,9 +41,13 @@ public override void Initialize()
private void OnLanguagesUpdated(LanguagesUpdatedMessage message)
{
+ // TODO this entire thing is horrible. If someone is willing to refactor this, LanguageSpeakerComponent should become shared with SendOnlyToOwner = true
+ // That way, this system will be able to use the existing networking infrastructure instead of relying on this makeshift... whatever this is.
CurrentLanguage = message.CurrentLanguage;
SpokenLanguages = message.Spoken;
UnderstoodLanguages = message.Understood;
+
+ OnLanguagesChanged?.Invoke(this, message);
}
private void OnRunLevelChanged(object? sender, RunLevelChangedEventArgs args)
diff --git a/Content.Client/Nutrition/EntitySystems/FoodGuideDataSystem.cs b/Content.Client/Nutrition/EntitySystems/FoodGuideDataSystem.cs
new file mode 100644
index 0000000000..37c7a25e21
--- /dev/null
+++ b/Content.Client/Nutrition/EntitySystems/FoodGuideDataSystem.cs
@@ -0,0 +1,30 @@
+using Content.Client.Chemistry.EntitySystems;
+using Robust.Shared.Prototypes;
+
+namespace Content.Client.Nutrition.EntitySystems;
+
+public sealed class FoodGuideDataSystem : SharedFoodGuideDataSystem
+{
+ public override void Initialize()
+ {
+ SubscribeNetworkEvent(OnReceiveRegistryUpdate);
+ }
+
+ private void OnReceiveRegistryUpdate(FoodGuideRegistryChangedEvent message)
+ {
+ Registry = message.Changeset;
+ }
+
+ public bool TryGetData(EntProtoId result, out FoodGuideEntry entry)
+ {
+ var index = Registry.FindIndex(it => it.Result == result);
+ if (index == -1)
+ {
+ entry = default;
+ return false;
+ }
+
+ entry = Registry[index];
+ return true;
+ }
+}
diff --git a/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs b/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs
index 3d8ae50748..198eb5e4fb 100644
--- a/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs
+++ b/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs
@@ -97,6 +97,12 @@ private void HandleToggleWalk(BaseButton.ButtonToggledEventArgs args)
_deferCommands.Add(_inputManager.SaveToUserData);
}
+ private void HandleDefaultWalk(BaseButton.ButtonToggledEventArgs args)
+ {
+ _cfg.SetCVar(CCVars.DefaultWalk, args.Pressed);
+ _cfg.SaveToFile();
+ }
+
private void HandleStaticStorageUI(BaseButton.ButtonToggledEventArgs args)
{
_cfg.SetCVar(CCVars.StaticStorageUI, args.Pressed);
@@ -161,6 +167,7 @@ void AddCheckBox(string checkBoxName, bool currentState, Action(OnUpdatePredicted);
SubscribeLocalEvent(OnUpdateRelayTargetPredicted);
SubscribeLocalEvent(OnUpdatePullablePredicted);
+
+ Subs.CVar(_config, CCVars.DefaultWalk, _ => RaiseNetworkEvent(new UpdateInputCVarsMessage()));
}
private void OnUpdatePredicted(EntityUid uid, InputMoverComponent component, ref UpdateIsPredictedEvent args)
diff --git a/Content.Client/RCD/RCDMenu.xaml.cs b/Content.Client/RCD/RCDMenu.xaml.cs
index 51ec66ea44..3eb0397a69 100644
--- a/Content.Client/RCD/RCDMenu.xaml.cs
+++ b/Content.Client/RCD/RCDMenu.xaml.cs
@@ -68,7 +68,7 @@ public RCDMenu(EntityUid owner, RCDMenuBoundUserInterface bui)
tooltip = Loc.GetString(entProto.Name);
}
- tooltip = char.ToUpper(tooltip[0]) + tooltip.Remove(0, 1);
+ tooltip = OopsConcat(char.ToUpper(tooltip[0]).ToString(), tooltip.Remove(0, 1));
var button = new RCDMenuButton()
{
@@ -119,6 +119,12 @@ public RCDMenu(EntityUid owner, RCDMenuBoundUserInterface bui)
SendRCDSystemMessageAction += bui.SendRCDSystemMessage;
}
+ private static string OopsConcat(string a, string b)
+ {
+ // This exists to prevent Roslyn being clever and compiling something that fails sandbox checks.
+ return a + b;
+ }
+
private void AddRCDMenuButtonOnClickActions(Control control)
{
var radialContainer = control as RadialContainer;
diff --git a/Content.Client/ShortConstruction/UI/ShortConstructionMenuBUI.cs b/Content.Client/ShortConstruction/UI/ShortConstructionMenuBUI.cs
index 37606d8656..4d50d91e16 100644
--- a/Content.Client/ShortConstruction/UI/ShortConstructionMenuBUI.cs
+++ b/Content.Client/ShortConstruction/UI/ShortConstructionMenuBUI.cs
@@ -66,7 +66,7 @@ private RadialMenu FormMenu()
var mainContainer = new RadialContainer
{
- Radius = 36f / MathF.Sin(MathF.PI / crafting.Prototypes.Count)
+ Radius = 36f / MathF.Sin(MathF.PI / 2f / crafting.Prototypes.Count)
};
foreach (var protoId in crafting.Prototypes)
diff --git a/Content.Client/UserInterface/Systems/Language/LanguageMenuUIController.cs b/Content.Client/UserInterface/Systems/Language/LanguageMenuUIController.cs
index f36521ce81..e351a16bfb 100644
--- a/Content.Client/UserInterface/Systems/Language/LanguageMenuUIController.cs
+++ b/Content.Client/UserInterface/Systems/Language/LanguageMenuUIController.cs
@@ -2,7 +2,6 @@
using Content.Client.Gameplay;
using Content.Client.UserInterface.Controls;
using Content.Shared.Input;
-using Content.Shared.Language.Events;
using Robust.Client.UserInterface.Controllers;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Input.Binding;
@@ -18,12 +17,6 @@ public sealed class LanguageMenuUIController : UIController, IOnStateEntered UIManager.GetActiveUIWidgetOrNull()?.LanguageButton;
- public override void Initialize()
- {
- SubscribeNetworkEvent((LanguagesUpdatedMessage message, EntitySessionEventArgs _) =>
- LanguageWindow?.UpdateState(message.CurrentLanguage, message.Spoken));
- }
-
public void OnStateEntered(GameplayState state)
{
DebugTools.Assert(LanguageWindow == null);
@@ -31,6 +24,17 @@ public void OnStateEntered(GameplayState state)
LanguageWindow = UIManager.CreateWindow();
LayoutContainer.SetAnchorPreset(LanguageWindow, LayoutContainer.LayoutPreset.CenterTop);
+ LanguageWindow.OnClose += () =>
+ {
+ if (LanguageButton != null)
+ LanguageButton.Pressed = false;
+ };
+ LanguageWindow.OnOpen += () =>
+ {
+ if (LanguageButton != null)
+ LanguageButton.Pressed = true;
+ };
+
CommandBinds.Builder.Bind(ContentKeyFunctions.OpenLanguageMenu,
InputCmdHandler.FromDelegate(_ => ToggleWindow())).Register();
}
@@ -60,12 +64,6 @@ public void LoadButton()
return;
LanguageButton.OnPressed += LanguageButtonPressed;
-
- if (LanguageWindow == null)
- return;
-
- LanguageWindow.OnClose += () => LanguageButton.Pressed = false;
- LanguageWindow.OnOpen += () => LanguageButton.Pressed = true;
}
private void LanguageButtonPressed(ButtonEventArgs args)
diff --git a/Content.IntegrationTests/Tests/Slipping/SlippingTest.cs b/Content.IntegrationTests/Tests/Slipping/SlippingTest.cs
index 61dcc3331d..28da7a9465 100644
--- a/Content.IntegrationTests/Tests/Slipping/SlippingTest.cs
+++ b/Content.IntegrationTests/Tests/Slipping/SlippingTest.cs
@@ -34,7 +34,7 @@ private void OnSlip(EntityUid uid, SlipperyComponent component, ref SlipEvent ar
public async Task BananaSlipTest()
{
var sys = SEntMan.System();
- var sprintWalks = sys.Config.GetCVar(CCVars.GamePressToSprint);
+ var sprintWalks = sys.Config.GetCVar(CCVars.DefaultWalk);
await SpawnTarget("TrashBananaPeel");
// var modifier = Comp(Player).SprintSpeedModifier;
diff --git a/Content.Server/Body/Components/BloodstreamComponent.cs b/Content.Server/Body/Components/BloodstreamComponent.cs
index dd93da9598..a272d5f365 100644
--- a/Content.Server/Body/Components/BloodstreamComponent.cs
+++ b/Content.Server/Body/Components/BloodstreamComponent.cs
@@ -181,9 +181,9 @@ public sealed partial class BloodstreamComponent : Component
public bool HasBloodDeficiency = false;
///
- /// How much reagent of blood should be removed with blood deficiency in each update interval?
+ /// How much percentage of max blood volume should be removed with blood deficiency in each update interval?
///
[DataField]
- public FixedPoint2 BloodDeficiencyLossAmount;
+ public float BloodDeficiencyLossPercentage;
}
}
diff --git a/Content.Server/Body/Systems/BloodstreamSystem.cs b/Content.Server/Body/Systems/BloodstreamSystem.cs
index b37ac5efeb..91ed7a2480 100644
--- a/Content.Server/Body/Systems/BloodstreamSystem.cs
+++ b/Content.Server/Body/Systems/BloodstreamSystem.cs
@@ -122,7 +122,7 @@ public override void Update(float frameTime)
if (bloodstream.HasBloodDeficiency)
{
if (!_mobStateSystem.IsDead(uid))
- RemoveBlood(uid, bloodstream.BloodDeficiencyLossAmount, bloodstream);
+ RemoveBlood(uid, bloodstream.BloodMaxVolume * bloodstream.BloodDeficiencyLossPercentage, bloodstream);
}
// Adds blood to their blood level if it is below the maximum.
else if (bloodSolution.Volume < bloodSolution.MaxVolume && !_mobStateSystem.IsDead(uid))
@@ -349,6 +349,14 @@ public void SetBloodLossThreshold(EntityUid uid, float threshold, BloodstreamCom
comp.BloodlossThreshold = threshold;
}
+ public void SetBloodMaxVolume(EntityUid uid, FixedPoint2 volume, BloodstreamComponent? comp = null)
+ {
+ if (!Resolve(uid, ref comp))
+ return;
+
+ comp.BloodMaxVolume = volume;
+ }
+
///
/// Attempts to modify the blood level of this entity directly.
///
diff --git a/Content.Server/Chemistry/ReagentEffects/ChemAddMoodlet.cs b/Content.Server/Chemistry/ReagentEffects/ChemAddMoodlet.cs
new file mode 100644
index 0000000000..f5bb629299
--- /dev/null
+++ b/Content.Server/Chemistry/ReagentEffects/ChemAddMoodlet.cs
@@ -0,0 +1,34 @@
+using Content.Shared.Chemistry.Reagent;
+using Content.Shared.Mood;
+using JetBrains.Annotations;
+using Robust.Shared.Prototypes;
+
+namespace Content.Server.Chemistry.ReagentEffects;
+
+///
+/// Adds a moodlet to an entity.
+///
+[UsedImplicitly]
+public sealed partial class ChemAddMoodlet : ReagentEffect
+{
+ protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+ {
+ var protoMan = IoCManager.Resolve();
+ return Loc.GetString("reagent-effect-guidebook-add-moodlet",
+ ("amount", protoMan.Index(MoodPrototype.Id).MoodChange),
+ ("timeout", protoMan.Index(MoodPrototype.Id).Timeout));
+ }
+
+ ///
+ /// The mood prototype to be applied to the using entity.
+ ///
+ [DataField(required: true)]
+ public ProtoId MoodPrototype = default!;
+
+ public override void Effect(ReagentEffectArgs args)
+ {
+ var entityManager = IoCManager.Resolve();
+ var ev = new MoodEffectEvent(MoodPrototype);
+ entityManager.EventBus.RaiseLocalEvent(args.SolutionEntity, ev);
+ }
+}
diff --git a/Content.Server/Flight/FlightSystem.cs b/Content.Server/Flight/FlightSystem.cs
new file mode 100644
index 0000000000..e056fc24ec
--- /dev/null
+++ b/Content.Server/Flight/FlightSystem.cs
@@ -0,0 +1,158 @@
+
+using Content.Shared.Cuffs.Components;
+using Content.Shared.Damage.Components;
+using Content.Shared.DoAfter;
+using Content.Shared.Flight;
+using Content.Shared.Flight.Events;
+using Content.Shared.Mobs;
+using Content.Shared.Popups;
+using Content.Shared.Stunnable;
+using Content.Shared.Zombies;
+using Robust.Shared.Audio.Systems;
+
+namespace Content.Server.Flight;
+public sealed class FlightSystem : SharedFlightSystem
+{
+ [Dependency] private readonly SharedAudioSystem _audio = default!;
+ [Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
+ [Dependency] private readonly SharedPopupSystem _popupSystem = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnToggleFlight);
+ SubscribeLocalEvent(OnFlightDoAfter);
+ SubscribeLocalEvent(OnMobStateChangedEvent);
+ SubscribeLocalEvent(OnZombified);
+ SubscribeLocalEvent(OnKnockedDown);
+ SubscribeLocalEvent(OnStunned);
+ SubscribeLocalEvent(OnSleep);
+ }
+ public override void Update(float frameTime)
+ {
+ base.Update(frameTime);
+
+ var query = EntityQueryEnumerator();
+ while (query.MoveNext(out var uid, out var component))
+ {
+ if (!component.On)
+ continue;
+
+ component.TimeUntilFlap -= frameTime;
+
+ if (component.TimeUntilFlap > 0f)
+ continue;
+
+ _audio.PlayPvs(component.FlapSound, uid);
+ component.TimeUntilFlap = component.FlapInterval;
+
+ }
+ }
+
+ #region Core Functions
+ private void OnToggleFlight(EntityUid uid, FlightComponent component, ToggleFlightEvent args)
+ {
+ // If the user isnt flying, we check for conditionals and initiate a doafter.
+ if (!component.On)
+ {
+ if (!CanFly(uid, component))
+ return;
+
+ var doAfterArgs = new DoAfterArgs(EntityManager,
+ uid, component.ActivationDelay,
+ new FlightDoAfterEvent(), uid, target: uid)
+ {
+ BlockDuplicate = true,
+ BreakOnTargetMove = true,
+ BreakOnUserMove = true,
+ BreakOnDamage = true,
+ NeedHand = true
+ };
+
+ if (!_doAfter.TryStartDoAfter(doAfterArgs))
+ return;
+ }
+ else
+ ToggleActive(uid, false, component);
+ }
+
+ private void OnFlightDoAfter(EntityUid uid, FlightComponent component, FlightDoAfterEvent args)
+ {
+ if (args.Handled || args.Cancelled)
+ return;
+
+ ToggleActive(uid, true, component);
+ args.Handled = true;
+ }
+
+ #endregion
+
+ #region Conditionals
+
+ private bool CanFly(EntityUid uid, FlightComponent component)
+ {
+ if (TryComp(uid, out var cuffableComp) && !cuffableComp.CanStillInteract)
+ {
+ _popupSystem.PopupEntity(Loc.GetString("no-flight-while-restrained"), uid, uid, PopupType.Medium);
+ return false;
+ }
+
+ if (HasComp(uid))
+ {
+ _popupSystem.PopupEntity(Loc.GetString("no-flight-while-zombified"), uid, uid, PopupType.Medium);
+ return false;
+ }
+ return true;
+ }
+
+ private void OnMobStateChangedEvent(EntityUid uid, FlightComponent component, MobStateChangedEvent args)
+ {
+ if (!component.On
+ || args.NewMobState is MobState.Critical or MobState.Dead)
+ return;
+
+ ToggleActive(args.Target, false, component);
+ }
+
+ private void OnZombified(EntityUid uid, FlightComponent component, ref EntityZombifiedEvent args)
+ {
+ if (!component.On)
+ return;
+
+ ToggleActive(args.Target, false, component);
+ if (!TryComp(uid, out var stamina))
+ return;
+ Dirty(uid, stamina);
+ }
+
+ private void OnKnockedDown(EntityUid uid, FlightComponent component, ref KnockedDownEvent args)
+ {
+ if (!component.On)
+ return;
+
+ ToggleActive(uid, false, component);
+ }
+
+ private void OnStunned(EntityUid uid, FlightComponent component, ref StunnedEvent args)
+ {
+ if (!component.On)
+ return;
+
+ ToggleActive(uid, false, component);
+ }
+
+ private void OnSleep(EntityUid uid, FlightComponent component, ref SleepStateChangedEvent args)
+ {
+ if (!component.On
+ || !args.FellAsleep)
+ return;
+
+ ToggleActive(uid, false, component);
+ if (!TryComp(uid, out var stamina))
+ return;
+
+ Dirty(uid, stamina);
+ }
+ #endregion
+}
\ No newline at end of file
diff --git a/Content.Server/HeightAdjust/BloodstreamAdjustSystem.cs b/Content.Server/HeightAdjust/BloodstreamAdjustSystem.cs
index 92e03e0c11..9ba0ee4b00 100644
--- a/Content.Server/HeightAdjust/BloodstreamAdjustSystem.cs
+++ b/Content.Server/HeightAdjust/BloodstreamAdjustSystem.cs
@@ -1,4 +1,5 @@
using Content.Server.Body.Components;
+using Content.Server.Body.Systems;
using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Shared.CCVar;
using Content.Shared.Chemistry.Reagent;
@@ -10,6 +11,7 @@ namespace Content.Server.HeightAdjust;
public sealed class BloodstreamAdjustSystem : EntitySystem
{
+ [Dependency] private readonly BloodstreamSystem _bloodstream = default!;
[Dependency] private readonly IConfigurationManager _config = default!;
[Dependency] private readonly ContestsSystem _contests = default!;
[Dependency] private readonly SolutionContainerSystem _solutionContainer = default!;
@@ -40,6 +42,8 @@ public bool TryAdjustBloodstream(Entity ent)
bloodSolution.MaxVolume = newVolume;
bloodSolution.SetContents([new ReagentQuantity(bloodstream.BloodReagent, newBloodLevel, null)], false);
+ _bloodstream.SetBloodMaxVolume(ent.Owner, newVolume, bloodstream);
+
return true;
}
}
diff --git a/Content.Server/Language/TranslatorSystem.cs b/Content.Server/Language/TranslatorSystem.cs
index 6cdca12440..a893993e88 100644
--- a/Content.Server/Language/TranslatorSystem.cs
+++ b/Content.Server/Language/TranslatorSystem.cs
@@ -9,6 +9,7 @@
using Content.Shared.PowerCell;
using Content.Shared.Language.Components.Translators;
using Robust.Shared.Containers;
+using Robust.Shared.Timing;
namespace Content.Server.Language;
@@ -27,7 +28,7 @@ public override void Initialize()
SubscribeLocalEvent(OnProxyDetermineLanguages);
SubscribeLocalEvent(OnTranslatorInserted);
- SubscribeLocalEvent(OnTranslatorRemoved);
+ SubscribeLocalEvent(OnTranslatorParentChanged);
SubscribeLocalEvent(OnTranslatorToggle);
SubscribeLocalEvent(OnPowerCellSlotEmpty);
}
@@ -65,8 +66,7 @@ private void OnProxyDetermineLanguages(EntityUid uid, HoldsTranslatorComponent c
private void OnTranslatorInserted(EntityUid translator, HandheldTranslatorComponent component, EntGotInsertedIntoContainerMessage args)
{
- if (args.Container.Owner is not {Valid: true} holder
- || !EntityManager.HasComponent(holder))
+ if (args.Container.Owner is not {Valid: true} holder || !HasComp(holder))
return;
var intrinsic = EnsureComp(holder);
@@ -75,14 +75,19 @@ private void OnTranslatorInserted(EntityUid translator, HandheldTranslatorCompon
_language.UpdateEntityLanguages(holder);
}
- private void OnTranslatorRemoved(EntityUid translator, HandheldTranslatorComponent component, EntGotRemovedFromContainerMessage args)
+ private void OnTranslatorParentChanged(EntityUid translator, HandheldTranslatorComponent component, EntParentChangedMessage args)
{
- if (args.Container.Owner is not {Valid: true} holder
- || !EntityManager.TryGetComponent(holder, out var intrinsic))
+ if (!HasComp(args.OldParent))
return;
- intrinsic.Translators.RemoveWhere(it => it.Owner == translator);
- _language.UpdateEntityLanguages(holder);
+ // Update the translator on the next tick - this is necessary because there's a good chance the removal from a container
+ // Was caused by the player moving the translator within their inventory rather than removing it.
+ // If that is not the case, then OnProxyDetermineLanguages will remove this translator from HoldsTranslatorComponent.Translators.
+ Timer.Spawn(0, () =>
+ {
+ if (Exists(args.OldParent) && TryComp(args.OldParent, out var speaker))
+ _language.UpdateEntityLanguages(args.OldParent.Value, speaker);
+ });
}
private void OnTranslatorToggle(EntityUid translator, HandheldTranslatorComponent translatorComp, ActivateInWorldEvent args)
@@ -125,6 +130,9 @@ private void OnPowerCellSlotEmpty(EntityUid translator, HandheldTranslatorCompon
component.Enabled = false;
_powerCell.SetPowerCellDrawEnabled(translator, false);
OnAppearanceChange(translator, component);
+
+ if (_containers.TryGetContainingContainer(translator, out var holderCont) && TryComp(holderCont.Owner, out var languageComp))
+ _language.UpdateEntityLanguages(holderCont.Owner, languageComp);
}
private void CopyLanguages(BaseTranslatorComponent from, DetermineEntityLanguagesEvent to, LanguageKnowledgeComponent knowledge)
diff --git a/Content.Server/Medical/PenLightSystem.cs b/Content.Server/Medical/PenLightSystem.cs
index f48a84d047..0e0f22684a 100644
--- a/Content.Server/Medical/PenLightSystem.cs
+++ b/Content.Server/Medical/PenLightSystem.cs
@@ -1,4 +1,5 @@
using Content.Server.DoAfter;
+using Content.Server.Popups;
using Content.Server.PowerCell;
using Content.Shared.Damage;
using Content.Shared.DoAfter;
@@ -7,6 +8,7 @@
using Content.Shared.Eye.Blinding.Components;
using Content.Shared.Interaction;
using Content.Shared.Medical;
+using Content.Shared.Mobs.Components;
using Content.Shared.Mobs.Systems;
using Content.Shared.Traits.Assorted.Components;
using Robust.Server.GameObjects;
@@ -22,7 +24,9 @@ public sealed class PenLightSystem : EntitySystem
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly DoAfterSystem _doAfter = default!;
[Dependency] private readonly PowerCellSystem _powerCell = default!;
+ [Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
+
///
public override void Initialize()
{
@@ -30,20 +34,23 @@ public override void Initialize()
SubscribeLocalEvent(OnDoAfter);
}
- private void OnAfterInteract(EntityUid uid, PenLightComponent component, AfterInteractEvent args)
+ private void OnAfterInteract(EntityUid uid, PenLightComponent component, ref AfterInteractEvent args)
{
- if (args.Handled
- || args.Target is not { } target)
+ if (args.Handled
+ || args.Target is not {} target
+ || target == null
+ || !args.CanReach
+ || !HasComp(target)
+ || !_powerCell.HasDrawCharge(uid, user: args.User))
return;
-
args.Handled = TryStartExam(uid, target, args.User, component);
}
private void OnDoAfter(Entity uid, ref PenLightDoAfterEvent args)
{
- if (args.Handled
- || args.Cancelled
- || args.Target == null
+ if (args.Handled
+ || args.Cancelled
+ || args.Target == null
|| !_powerCell.HasDrawCharge(uid, user: args.User))
return;
@@ -52,6 +59,13 @@ private void OnDoAfter(Entity uid, ref PenLightDoAfterEvent a
args.Handled = true;
}
+ ///
+ /// Checks if the PointLight component is enabled.
+ ///
+ private bool IsLightEnabled(EntityUid uid)
+ {
+ return TryComp(uid, out var pointLight) && pointLight.Enabled;
+ }
///
/// Actually handles the exam interaction.
@@ -61,6 +75,18 @@ public bool TryStartExam(EntityUid uid, EntityUid target, EntityUid user, PenLig
if (!Resolve(uid, ref component))
return false;
+ if (!IsLightEnabled(uid))
+ {
+ if (user != null)
+ _popup.PopupEntity(Loc.GetString("penlight-off"), uid, user);
+ return false;
+ }
+ // can't examine your own eyes, dingus
+ if (user == target)
+ {
+ _popup.PopupEntity(Loc.GetString("penlight-cannot-examine-self"), uid, user);
+ return false;
+ }
return _doAfter.TryStartDoAfter(new DoAfterArgs(EntityManager, user, component.ExamSpeed, new PenLightDoAfterEvent(),
uid, target, uid)
{
@@ -73,7 +99,7 @@ public bool TryStartExam(EntityUid uid, EntityUid target, EntityUid user, PenLig
}
private void OpenUserInterface(EntityUid user, EntityUid penlight)
{
- if (!TryComp(user, out var actor)
+ if (!TryComp(user, out var actor)
|| !_uiSystem.TryGetUi(penlight, PenLightUiKey.Key, out var ui))
return;
@@ -86,8 +112,10 @@ private void OpenUserInterface(EntityUid user, EntityUid penlight)
private void Diagnose(EntityUid penlight, EntityUid target)
{
if (!_uiSystem.TryGetUi(penlight, PenLightUiKey.Key, out var ui)
- || !HasComp(target))
+ || !HasComp(target)
+ || !HasComp(target))
return;
+
// Blind
var blind = _entityManager.HasComponent(target);
diff --git a/Content.Server/Mood/MoodSystem.cs b/Content.Server/Mood/MoodSystem.cs
index f2dc87ffd6..7e4789bf14 100644
--- a/Content.Server/Mood/MoodSystem.cs
+++ b/Content.Server/Mood/MoodSystem.cs
@@ -53,8 +53,6 @@ public override void Initialize()
SubscribeLocalEvent(OnDamageChange);
SubscribeLocalEvent(OnRefreshMoveSpeed);
SubscribeLocalEvent(OnRemoveEffect);
-
- SubscribeLocalEvent(OnTraitStartup);
}
private void OnShutdown(EntityUid uid, MoodComponent component, ComponentShutdown args)
@@ -101,15 +99,6 @@ private void OnRefreshMoveSpeed(EntityUid uid, MoodComponent component, RefreshM
args.ModifySpeed(1, modifier);
}
- private void OnTraitStartup(EntityUid uid, MoodModifyTraitComponent component, ComponentStartup args)
- {
- if (_debugMode
- || component.MoodId is null)
- return;
-
- RaiseLocalEvent(uid, new MoodEffectEvent($"{component.MoodId}"));
- }
-
private void OnMoodEffect(EntityUid uid, MoodComponent component, MoodEffectEvent args)
{
if (_debugMode
@@ -195,9 +184,28 @@ private void RemoveTimedOutEffect(EntityUid uid, string prototypeId, string? cat
comp.CategorisedEffects.Remove(category);
}
+ ReplaceMood(uid, prototypeId);
RefreshMood(uid, comp);
}
+ ///
+ /// Some moods specifically create a moodlet upon expiration. This is normally used for "Addiction" type moodlets,
+ /// such as a positive moodlet from an addictive substance that becomes a negative moodlet when a timer ends.
+ ///
+ ///
+ /// Moodlets that use this should probably also share a category with each other, but this isn't necessarily required.
+ /// Only if you intend that "Re-using the drug" should also remove the negative moodlet.
+ ///
+ private void ReplaceMood(EntityUid uid, string prototypeId)
+ {
+ if (!_prototypeManager.TryIndex(prototypeId, out var proto)
+ || proto.MoodletOnEnd is null)
+ return;
+
+ var ev = new MoodEffectEvent(proto.MoodletOnEnd);
+ EntityManager.EventBus.RaiseLocalEvent(uid, ev);
+ }
+
private void OnMobStateChanged(EntityUid uid, MoodComponent component, MobStateChangedEvent args)
{
if (_debugMode)
diff --git a/Content.Server/Nutrition/EntitySystems/FoodGuideDataSystem.cs b/Content.Server/Nutrition/EntitySystems/FoodGuideDataSystem.cs
new file mode 100644
index 0000000000..f21c509ace
--- /dev/null
+++ b/Content.Server/Nutrition/EntitySystems/FoodGuideDataSystem.cs
@@ -0,0 +1,138 @@
+using System.Linq;
+using Content.Client.Chemistry.EntitySystems;
+using Content.Server.Chemistry.ReactionEffects;
+using Content.Server.Nutrition.Components;
+using Content.Shared.Chemistry.Components.SolutionManager;
+using Content.Shared.Chemistry.Reaction;
+using Content.Shared.Chemistry.Reagent;
+using Content.Shared.Kitchen;
+using Content.Shared.Nutrition.Components;
+using Robust.Server.Player;
+using Robust.Shared.Enums;
+using Robust.Shared.Player;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Utility;
+
+namespace Content.Server.Nutrition.EntitySystems;
+
+public sealed class FoodGuideDataSystem : SharedFoodGuideDataSystem
+{
+ public static readonly ProtoId[] ReagentWhitelist =
+ [
+ "Nutriment",
+ "Vitamin",
+ "Protein",
+ "UncookedAnimalProteins",
+ "Fat",
+ "Water"
+ ];
+
+ public static readonly string[] ComponentNamesBlacklist = ["HumanoidAppearance"];
+
+ public static readonly string[] SuffixBlacklist = ["debug", "do not map", "admeme"];
+
+ [Dependency] private readonly IPlayerManager _player = default!;
+ [Dependency] private readonly IPrototypeManager _protoMan = default!;
+
+ private Dictionary> _sources = new();
+
+ public override void Initialize()
+ {
+ SubscribeLocalEvent(OnPrototypesReloaded);
+ _player.PlayerStatusChanged += OnPlayerStatusChanged;
+
+ ReloadRecipes();
+ }
+
+ private void OnPrototypesReloaded(PrototypesReloadedEventArgs args)
+ {
+ if (!args.WasModified()
+ && !args.WasModified()
+ && !args.WasModified()
+ )
+ return;
+
+ ReloadRecipes();
+ }
+
+ public void ReloadRecipes()
+ {
+ // TODO: add this code to the list of known recipes because this is spaghetti
+ _sources.Clear();
+
+ // Butcherable and slicable entities
+ foreach (var ent in _protoMan.EnumeratePrototypes())
+ {
+ if (ent.Abstract
+ || ent.Components.Any(it => ComponentNamesBlacklist.Contains(it.Key))
+ || ent.SetSuffix is {} suffix && SuffixBlacklist.Any(it => suffix.Contains(it, StringComparison.OrdinalIgnoreCase))
+ )
+ continue;
+
+ if (ent.TryGetComponent(out var butcherable))
+ {
+ var butcheringSource = new FoodButcheringData(ent, butcherable);
+ foreach (var butchlet in butcherable.SpawnedEntities)
+ {
+ if (butchlet.PrototypeId is null)
+ continue;
+
+ _sources.GetOrNew(butchlet.PrototypeId).Add(butcheringSource);
+ }
+ }
+
+ if (ent.TryGetComponent(out var slicable) && slicable.Slice is not null)
+ {
+ _sources.GetOrNew(slicable.Slice).Add(new FoodSlicingData(ent, slicable.Slice.Value, slicable.TotalCount));
+ }
+ }
+
+ // Recipes
+ foreach (var recipe in _protoMan.EnumeratePrototypes())
+ {
+ _sources.GetOrNew(recipe.Result).Add(new FoodRecipeData(recipe));
+ }
+
+ // Entity-spawning reactions
+ foreach (var reaction in _protoMan.EnumeratePrototypes())
+ {
+ foreach (var effect in reaction.Effects)
+ {
+ if (effect is not CreateEntityReactionEffect entEffect)
+ continue;
+
+ _sources.GetOrNew(entEffect.Entity).Add(new FoodReactionData(reaction, entEffect.Entity, (int) entEffect.Number));
+ }
+ }
+
+ Registry.Clear();
+
+ foreach (var (result, sources) in _sources)
+ {
+ var proto = _protoMan.Index(result);
+ var composition = proto.TryGetComponent(out var food) && proto.TryGetComponent(out var manager)
+ ? manager?.Solutions?[food.Solution]?.Contents?.ToArray() ?? []
+ : [];
+
+ // We filter out food without whitelisted reagents because well when people look for food they usually expect FOOD and not insulated gloves.
+ // And we get insulated and other gloves because they have ButcherableComponent and they are also moth food
+ if (!composition.Any(it => ReagentWhitelist.Contains(it.Reagent.Prototype)))
+ continue;
+
+ // We also limit the number of sources to 10 because it's a huge performance strain to render 500 raw meat recipes.
+ var distinctSources = sources.DistinctBy(it => it.Identitier).Take(10);
+ var entry = new FoodGuideEntry(result, proto.Name, distinctSources.ToArray(), composition);
+ Registry.Add(entry);
+ }
+
+ RaiseNetworkEvent(new FoodGuideRegistryChangedEvent(Registry));
+ }
+
+ private void OnPlayerStatusChanged(object? sender, SessionStatusEventArgs args)
+ {
+ if (args.NewStatus != SessionStatus.Connected)
+ return;
+
+ RaiseNetworkEvent(new FoodGuideRegistryChangedEvent(Registry), args.Session);
+ }
+}
diff --git a/Content.Server/Power/Components/ActiveChargerComponent.cs b/Content.Server/Power/Components/ActiveChargerComponent.cs
new file mode 100644
index 0000000000..9f75db853d
--- /dev/null
+++ b/Content.Server/Power/Components/ActiveChargerComponent.cs
@@ -0,0 +1,7 @@
+using Content.Shared.Containers.ItemSlots;
+using Content.Shared.Power;
+
+namespace Content.Server.Power.Components;
+
+[RegisterComponent]
+public sealed partial class ActiveChargerComponent : Component { }
diff --git a/Content.Server/Power/Components/ChargingComponent.cs b/Content.Server/Power/Components/ChargingComponent.cs
deleted file mode 100644
index db7c14f708..0000000000
--- a/Content.Server/Power/Components/ChargingComponent.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using Content.Shared.Containers.ItemSlots;
-using Content.Shared.Power;
-
-namespace Content.Server.Power.Components
-{
- [RegisterComponent]
- public sealed partial class ChargingComponent : Component
- {
- ///
- ///References the entity of the charger that is currently powering this battery
- ///
- public EntityUid ChargerUid;
-
- ///
- ///References the component of the charger that is currently powering this battery
- ///
- public ChargerComponent ChargerComponent;
- }
-}
diff --git a/Content.Server/Power/EntitySystems/BatterySystem.cs b/Content.Server/Power/EntitySystems/BatterySystem.cs
index 1c5d83b094..cbe61f6671 100644
--- a/Content.Server/Power/EntitySystems/BatterySystem.cs
+++ b/Content.Server/Power/EntitySystems/BatterySystem.cs
@@ -21,7 +21,6 @@ public override void Initialize()
SubscribeLocalEvent(OnBatteryRejuvenate);
SubscribeLocalEvent(CalculateBatteryPrice);
SubscribeLocalEvent(OnEmpPulse);
- SubscribeLocalEvent(OnEmpDisabledRemoved);
SubscribeLocalEvent(PreSync);
SubscribeLocalEvent(PostSync);
@@ -106,17 +105,6 @@ private void OnEmpPulse(EntityUid uid, BatteryComponent component, ref EmpPulseE
UseCharge(uid, args.EnergyConsumption, component);
}
- // if a disabled battery is put into a recharged,
- // allow the recharger to start recharging again after the disable ends
- private void OnEmpDisabledRemoved(EntityUid uid, BatteryComponent component, ref EmpDisabledRemoved args)
- {
- if (!TryComp(uid, out var charging))
- return;
-
- var ev = new ChargerUpdateStatusEvent();
- RaiseLocalEvent(charging.ChargerUid, ref ev);
- }
-
public float UseCharge(EntityUid uid, float value, BatteryComponent? battery = null)
{
if (value <= 0 || !Resolve(uid, ref battery) || battery.CurrentCharge == 0)
@@ -191,10 +179,6 @@ public bool IsFull(EntityUid uid, BatteryComponent? battery = null)
if (!Resolve(uid, ref battery))
return false;
- // If the battery is full, remove its charging component.
- if (TryComp(uid, out _))
- RemComp(uid);
-
return battery.CurrentCharge / battery.MaxCharge >= 0.99f;
}
}
diff --git a/Content.Server/Power/EntitySystems/ChargerSystem.cs b/Content.Server/Power/EntitySystems/ChargerSystem.cs
index ae6b024162..db16dfa008 100644
--- a/Content.Server/Power/EntitySystems/ChargerSystem.cs
+++ b/Content.Server/Power/EntitySystems/ChargerSystem.cs
@@ -1,16 +1,13 @@
using Content.Server.Power.Components;
-using Content.Server.Emp;
using Content.Server.PowerCell;
using Content.Shared.Examine;
using Content.Shared.Power;
using Content.Shared.PowerCell.Components;
-using Content.Shared.Emp;
using JetBrains.Annotations;
using Robust.Shared.Containers;
using System.Diagnostics.CodeAnalysis;
using Content.Shared.Storage.Components;
using Robust.Server.Containers;
-using Content.Shared.Whitelist;
namespace Content.Server.Power.EntitySystems;
@@ -31,11 +28,6 @@ public override void Initialize()
SubscribeLocalEvent(OnInsertAttempt);
SubscribeLocalEvent(OnEntityStorageInsertAttempt);
SubscribeLocalEvent(OnChargerExamine);
-
- SubscribeLocalEvent(OnUpdateStatus);
-
- SubscribeLocalEvent(OnEmpPulse);
- SubscribeLocalEvent(OnEmpDisabledRemoved);
}
private void OnStartup(EntityUid uid, ChargerComponent component, ComponentStartup args)
@@ -48,58 +40,21 @@ private void OnChargerExamine(EntityUid uid, ChargerComponent component, Examine
args.PushMarkup(Loc.GetString("charger-examine", ("color", "yellow"), ("chargeRate", (int) component.ChargeRate)));
}
- private void StartChargingBattery(EntityUid uid, ChargerComponent component, EntityUid target)
- {
- bool charge = true;
-
- if (HasComp(uid))
- charge = false;
- else
- if (!TryComp(target, out var battery))
- charge = false;
- else
- if (Math.Abs(battery.MaxCharge - battery.CurrentCharge) < 0.01)
- charge = false;
-
- // wrap functionality in an if statement instead of returning...
- if (charge)
- {
- var charging = EnsureComp(target);
- charging.ChargerUid = uid;
- charging.ChargerComponent = component;
- }
-
- // ...so the status always updates (for insertin a power cell)
- UpdateStatus(uid, component);
- }
-
- private void StopChargingBattery(EntityUid uid, ChargerComponent component, EntityUid target)
- {
- if (HasComp(target))
- RemComp(target);
- UpdateStatus(uid, component);
- }
-
public override void Update(float frameTime)
{
- var query = EntityQueryEnumerator();
- while (query.MoveNext(out var uid, out var charging))
+ var query = EntityQueryEnumerator();
+ while (query.MoveNext(out var uid, out _, out var charger, out var containerComp))
{
- if (!TryComp(charging.ChargerUid, out var chargerComponent))
+ if (!_container.TryGetContainer(uid, charger.SlotId, out var container, containerComp))
continue;
- if (charging.ChargerComponent.Status == CellChargerStatus.Off || charging.ChargerComponent.Status == CellChargerStatus.Empty)
+ if (charger.Status == CellChargerStatus.Empty || charger.Status == CellChargerStatus.Charged || container.ContainedEntities.Count == 0)
continue;
- if (HasComp(charging.ChargerUid))
- continue;
-
- if (!TryComp(uid, out var battery))
- continue;
-
- if (Math.Abs(battery.MaxCharge - battery.CurrentCharge) < 0.01)
- StopChargingBattery(charging.ChargerUid, charging.ChargerComponent, uid);
- TransferPower(charging.ChargerUid, uid, charging.ChargerComponent, frameTime);
+ foreach (var contained in container.ContainedEntities)
+ {
+ TransferPower(uid, contained, charger, frameTime);
+ }
}
}
@@ -116,7 +71,7 @@ private void OnInserted(EntityUid uid, ChargerComponent component, EntInsertedIn
if (args.Container.ID != component.SlotId)
return;
- StartChargingBattery(uid, component, args.Entity);
+ UpdateStatus(uid, component);
}
private void OnRemoved(EntityUid uid, ChargerComponent component, EntRemovedFromContainerMessage args)
@@ -124,7 +79,7 @@ private void OnRemoved(EntityUid uid, ChargerComponent component, EntRemovedFrom
if (args.Container.ID != component.SlotId)
return;
- StopChargingBattery(uid, component, args.Entity);
+ UpdateStatus(uid, component);
}
///
@@ -157,11 +112,6 @@ private void OnEntityStorageInsertAttempt(EntityUid uid, ChargerComponent compon
args.Cancelled = true;
}
- private void OnUpdateStatus(EntityUid uid, ChargerComponent component, ref ChargerUpdateStatusEvent args)
- {
- UpdateStatus(uid, component);
- }
-
private void UpdateStatus(EntityUid uid, ChargerComponent component)
{
var status = GetStatus(uid, component);
@@ -176,6 +126,15 @@ private void UpdateStatus(EntityUid uid, ChargerComponent component)
component.Status = status;
+ if (component.Status == CellChargerStatus.Charging)
+ {
+ AddComp(uid);
+ }
+ else
+ {
+ RemComp(uid);
+ }
+
switch (component.Status)
{
case CellChargerStatus.Off:
@@ -187,7 +146,7 @@ private void UpdateStatus(EntityUid uid, ChargerComponent component)
_appearance.SetData(uid, CellVisual.Light, CellChargerStatus.Empty, appearance);
break;
case CellChargerStatus.Charging:
- receiver.Load = component.ChargeRate; //does not scale with multiple slotted batteries
+ receiver.Load = component.ChargeRate;
_appearance.SetData(uid, CellVisual.Light, CellChargerStatus.Charging, appearance);
break;
case CellChargerStatus.Charged:
@@ -198,42 +157,6 @@ private void UpdateStatus(EntityUid uid, ChargerComponent component)
throw new ArgumentOutOfRangeException();
}
}
-
- private void OnEmpPulse(EntityUid uid, ChargerComponent component, ref EmpPulseEvent args)
- {
- // we don't care if we haven't been disabled
- if (!args.Disabled)
- return;
-
- // if the recharger is hit by an emp pulse,
- // stop recharging contained batteries to save resources
- if (!_container.TryGetContainer(uid, component.SlotId, out var container))
- return;
-
- foreach (var containedEntity in container.ContainedEntities)
- {
- if (!SearchForBattery(containedEntity, out _, out _))
- continue;
-
- StopChargingBattery(uid, component, containedEntity);
- }
- }
-
- private void OnEmpDisabledRemoved(EntityUid uid, ChargerComponent component, ref EmpDisabledRemoved args)
- {
- // if an emp disable subsides,
- // attempt to start charging all batteries
- if (!_container.TryGetContainer(uid, component.SlotId, out var container))
- return;
-
- foreach (var containedEntity in container.ContainedEntities)
- {
- if (!SearchForBattery(containedEntity, out _, out _))
- continue;
-
- StartChargingBattery(uid, component, containedEntity);
- }
- }
private CellChargerStatus GetStatus(EntityUid uid, ChargerComponent component)
{
@@ -255,28 +178,13 @@ private CellChargerStatus GetStatus(EntityUid uid, ChargerComponent component)
if (container.ContainedEntities.Count == 0)
return CellChargerStatus.Empty;
- var statusOut = CellChargerStatus.Off;
-
- foreach (var containedEntity in container.ContainedEntities)
- {
- // if none of the slotted items are actually batteries, represent the charger as off
- if (!SearchForBattery(containedEntity, out _, out _))
- continue;
-
- // if all batteries are either EMP'd or fully charged, represent the charger as fully charged
- statusOut = CellChargerStatus.Charged;
- if (HasComp(containedEntity))
- continue;
-
- if (!HasComp(containedEntity))
- continue;
+ if (!SearchForBattery(container.ContainedEntities[0], out _, out var heldBattery))
+ return CellChargerStatus.Off;
- // if we have atleast one battery being charged, represent the charger as charging;
- statusOut = CellChargerStatus.Charging;
- break;
- }
+ if (Math.Abs(heldBattery.MaxCharge - heldBattery.CurrentCharge) < 0.01)
+ return CellChargerStatus.Charged;
- return statusOut;
+ return CellChargerStatus.Charging;
}
private void TransferPower(EntityUid uid, EntityUid targetEntity, ChargerComponent component, float frameTime)
@@ -293,11 +201,11 @@ private void TransferPower(EntityUid uid, EntityUid targetEntity, ChargerCompone
if (!SearchForBattery(targetEntity, out var batteryUid, out var heldBattery))
return;
- _battery.TrySetCharge(batteryUid.Value, heldBattery.CurrentCharge + component.ChargeRate * frameTime, heldBattery);
+ _battery.SetCharge(batteryUid.Value, heldBattery.CurrentCharge + component.ChargeRate * frameTime, heldBattery);
// Just so the sprite won't be set to 99.99999% visibility
if (heldBattery.MaxCharge - heldBattery.CurrentCharge < 0.01)
{
- _battery.TrySetCharge(batteryUid.Value, heldBattery.MaxCharge, heldBattery);
+ _battery.SetCharge(batteryUid.Value, heldBattery.MaxCharge, heldBattery);
}
UpdateStatus(uid, component);
@@ -315,6 +223,3 @@ private bool SearchForBattery(EntityUid uid, [NotNullWhen(true)] out EntityUid?
return true;
}
}
-
-[ByRefEvent]
-public record struct ChargerUpdateStatusEvent();
\ No newline at end of file
diff --git a/Content.Server/Traits/Assorted/ModifyMoodTraitComponent.cs b/Content.Server/Traits/Assorted/ModifyMoodTraitComponent.cs
deleted file mode 100644
index f9ae3b36f3..0000000000
--- a/Content.Server/Traits/Assorted/ModifyMoodTraitComponent.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-namespace Content.Shared.Traits.Assorted.Components;
-
-///
-/// Used for traits that add a starting moodlet.
-///
-[RegisterComponent]
-public sealed partial class MoodModifyTraitComponent : Component
-{
- [DataField]
- public string? MoodId = null;
-}
diff --git a/Content.Server/Traits/BloodDeficiencyComponent.cs b/Content.Server/Traits/BloodDeficiencyComponent.cs
index 616f60cd83..c6219d3e02 100644
--- a/Content.Server/Traits/BloodDeficiencyComponent.cs
+++ b/Content.Server/Traits/BloodDeficiencyComponent.cs
@@ -7,8 +7,8 @@ namespace Content.Server.Traits.Assorted;
public sealed partial class BloodDeficiencyComponent : Component
{
//
- // How much reagent of blood should be removed in each update interval?
+ /// How much percentage of max blood volume should be removed in each update interval?
//
[DataField(required: true)]
- public float BloodLossAmount;
+ public float BloodLossPercentage;
}
diff --git a/Content.Server/Traits/BloodDeficiencySystem.cs b/Content.Server/Traits/BloodDeficiencySystem.cs
index f1ae490995..ee7a39e46e 100644
--- a/Content.Server/Traits/BloodDeficiencySystem.cs
+++ b/Content.Server/Traits/BloodDeficiencySystem.cs
@@ -18,6 +18,6 @@ private void OnStartup(EntityUid uid, BloodDeficiencyComponent component, Compon
return;
bloodstream.HasBloodDeficiency = true;
- bloodstream.BloodDeficiencyLossAmount = component.BloodLossAmount;
+ bloodstream.BloodDeficiencyLossPercentage = component.BloodLossPercentage;
}
}
diff --git a/Content.Server/Traits/TraitSystem.cs b/Content.Server/Traits/TraitSystem.cs
index d6f13cb52a..39812f65b6 100644
--- a/Content.Server/Traits/TraitSystem.cs
+++ b/Content.Server/Traits/TraitSystem.cs
@@ -12,6 +12,7 @@
using Robust.Shared.Utility;
using Content.Server.Abilities.Psionics;
using Content.Shared.Psionics;
+using Content.Shared.Mood;
namespace Content.Server.Traits;
@@ -65,6 +66,7 @@ public void AddTrait(EntityUid uid, TraitPrototype traitPrototype)
AddTraitComponents(uid, traitPrototype);
AddTraitActions(uid, traitPrototype);
AddTraitPsionics(uid, traitPrototype);
+ AddTraitMoodlets(uid, traitPrototype);
}
///
@@ -139,4 +141,18 @@ public void AddTraitPsionics(EntityUid uid, TraitPrototype traitPrototype)
if (_prototype.TryIndex(powerProto, out var psionicPower))
_psionicAbilities.InitializePsionicPower(uid, psionicPower, false);
}
+
+ ///
+ /// If a trait includes any moodlets, this adds the moodlets to the receiving entity.
+ /// While I can't stop you, you shouldn't use this to add temporary moodlets.
+ ///
+ public void AddTraitMoodlets(EntityUid uid, TraitPrototype traitPrototype)
+ {
+ if (traitPrototype.MoodEffects is null)
+ return;
+
+ foreach (var moodProto in traitPrototype.MoodEffects)
+ if (_prototype.TryIndex(moodProto, out var moodlet))
+ RaiseLocalEvent(uid, new MoodEffectEvent(moodlet.ID));
+ }
}
diff --git a/Content.Shared/CCVar/CCVars.cs b/Content.Shared/CCVar/CCVars.cs
index d52c442f30..de8bc81312 100644
--- a/Content.Shared/CCVar/CCVars.cs
+++ b/Content.Shared/CCVar/CCVars.cs
@@ -404,13 +404,6 @@ public static readonly CVarDef
public static readonly CVarDef GameAutoEatDrinks =
CVarDef.Create("game.auto_eat_drinks", false, CVar.REPLICATED);
-
- ///
- /// When true, you have to press the change speed button to sprint.
- ///
- public static readonly CVarDef GamePressToSprint =
- CVarDef.Create("game.press_to_sprint", true, CVar.REPLICATED);
-
///
/// Whether item slots, such as power cell slots or AME fuel cell slots, should support quick swap if it is not otherwise specified in their YAML prototype.
///
@@ -2006,6 +1999,12 @@ public static readonly CVarDef
public static readonly CVarDef ToggleWalk =
CVarDef.Create("control.toggle_walk", false, CVar.CLIENTONLY | CVar.ARCHIVE);
+ ///
+ /// Whether the player mob is walking by default instead of running.
+ ///
+ public static readonly CVarDef DefaultWalk =
+ CVarDef.Create("control.default_walk", true, CVar.CLIENT | CVar.REPLICATED | CVar.ARCHIVE);
+
/*
* STORAGE
*/
@@ -2467,5 +2466,21 @@ public static readonly CVarDef
CVarDef.Create("reclaimer.allow_gibbing", true, CVar.SERVER);
#endregion
+
+ #region Jetpack System
+
+ ///
+ /// When true, Jetpacks can be enabled anywhere, even in gravity.
+ ///
+ public static readonly CVarDef JetpackEnableAnywhere =
+ CVarDef.Create("jetpack.enable_anywhere", false, CVar.REPLICATED);
+
+ ///
+ /// When true, jetpacks can be enabled on grids that have zero gravity.
+ ///
+ public static readonly CVarDef JetpackEnableInNoGravity =
+ CVarDef.Create("jetpack.enable_in_no_gravity", true, CVar.REPLICATED);
+
+ #endregion
}
}
diff --git a/Content.Shared/Chat/SharedChatSystem.cs b/Content.Shared/Chat/SharedChatSystem.cs
index c48d70405f..efbcc9bed5 100644
--- a/Content.Shared/Chat/SharedChatSystem.cs
+++ b/Content.Shared/Chat/SharedChatSystem.cs
@@ -154,10 +154,16 @@ public string SanitizeMessageCapital(string message)
if (string.IsNullOrEmpty(message))
return message;
// Capitalize first letter
- message = char.ToUpper(message[0]) + message.Remove(0, 1);
+ message = OopsConcat(char.ToUpper(message[0]).ToString(), message.Remove(0, 1));
return message;
}
+ private static string OopsConcat(string a, string b)
+ {
+ // This exists to prevent Roslyn being clever and compiling something that fails sandbox checks.
+ return a + b;
+ }
+
public string SanitizeMessageCapitalizeTheWordI(string message, string theWordI = "i")
{
if (string.IsNullOrEmpty(message))
diff --git a/Content.Shared/Chemistry/EntitySystems/RehydratableSystem.cs b/Content.Shared/Chemistry/EntitySystems/RehydratableSystem.cs
index e260280ae4..44bfb583dd 100644
--- a/Content.Shared/Chemistry/EntitySystems/RehydratableSystem.cs
+++ b/Content.Shared/Chemistry/EntitySystems/RehydratableSystem.cs
@@ -1,12 +1,14 @@
using Content.Shared.Chemistry.Components;
using Content.Shared.FixedPoint;
using Content.Shared.Popups;
+using Robust.Shared.Network;
using Robust.Shared.Random;
namespace Content.Shared.Chemistry.EntitySystems;
public sealed class RehydratableSystem : EntitySystem
{
+ [Dependency] private readonly INetManager _net = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly SharedSolutionContainerSystem _solutions = default!;
@@ -31,6 +33,9 @@ private void OnSolutionChange(Entity ent, ref SolutionCon
// Try not to make this public if you can help it.
private void Expand(Entity ent)
{
+ if (_net.IsClient)
+ return; // no
+
var (uid, comp) = ent;
var randomMob = _random.Pick(comp.PossibleSpawns);
diff --git a/Content.Shared/Cuffs/SharedCuffableSystem.cs b/Content.Shared/Cuffs/SharedCuffableSystem.cs
index ebbafef7f0..9777b23988 100644
--- a/Content.Shared/Cuffs/SharedCuffableSystem.cs
+++ b/Content.Shared/Cuffs/SharedCuffableSystem.cs
@@ -7,6 +7,7 @@
using Content.Shared.Contests;
using Content.Shared.Cuffs.Components;
using Content.Shared.Database;
+using Content.Shared.Flight;
using Content.Shared.DoAfter;
using Content.Shared.Hands;
using Content.Shared.Hands.Components;
@@ -479,6 +480,13 @@ public bool TryCuffing(EntityUid user, EntityUid target, EntityUid handcuff, Han
return true;
}
+ if (TryComp(target, out var flight) && flight.On)
+ {
+ _popup.PopupClient(Loc.GetString("handcuff-component-target-flying-error",
+ ("targetName", Identity.Name(target, EntityManager, user))), user, user);
+ return true;
+ }
+
var cuffTime = handcuffComponent.CuffTime;
if (HasComp(target))
@@ -731,4 +739,4 @@ private sealed partial class AddCuffDoAfterEvent : SimpleDoAfterEvent
{
}
}
-}
+}
\ No newline at end of file
diff --git a/Content.Shared/Damage/Components/StaminaComponent.cs b/Content.Shared/Damage/Components/StaminaComponent.cs
index 65c025c3ad..b78fe97809 100644
--- a/Content.Shared/Damage/Components/StaminaComponent.cs
+++ b/Content.Shared/Damage/Components/StaminaComponent.cs
@@ -39,6 +39,13 @@ public sealed partial class StaminaComponent : Component
[ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField]
public float CritThreshold = 100f;
+ ///
+ /// A dictionary of active stamina drains, with the key being the source of the drain,
+ /// DrainRate how much it changes per tick, and ModifiesSpeed if it should slow down the user.
+ ///
+ [DataField, AutoNetworkedField]
+ public Dictionary ActiveDrains = new();
+
///
/// How long will this mob be stunned for?
///
@@ -63,4 +70,4 @@ public sealed partial class StaminaComponent : Component
///
[DataField, AutoNetworkedField]
public float SlowdownMultiplier = 0.75f;
-}
+}
\ No newline at end of file
diff --git a/Content.Shared/Damage/Systems/StaminaSystem.cs b/Content.Shared/Damage/Systems/StaminaSystem.cs
index f8a0f7c62b..e4840a6630 100644
--- a/Content.Shared/Damage/Systems/StaminaSystem.cs
+++ b/Content.Shared/Damage/Systems/StaminaSystem.cs
@@ -258,7 +258,7 @@ public bool TryTakeStamina(EntityUid uid, float value, StaminaComponent? compone
}
public void TakeStaminaDamage(EntityUid uid, float value, StaminaComponent? component = null,
- EntityUid? source = null, EntityUid? with = null, bool visual = true, SoundSpecifier? sound = null)
+ EntityUid? source = null, EntityUid? with = null, bool visual = true, SoundSpecifier? sound = null, bool? allowsSlowdown = true)
{
if (!Resolve(uid, ref component, false)
|| value == 0)
@@ -284,8 +284,8 @@ public void TakeStaminaDamage(EntityUid uid, float value, StaminaComponent? comp
if (component.NextUpdate < nextUpdate)
component.NextUpdate = nextUpdate;
}
-
- _movementSpeed.RefreshMovementSpeedModifiers(uid);
+ if (allowsSlowdown == true)
+ _movementSpeed.RefreshMovementSpeedModifiers(uid);
SetStaminaAlert(uid, component);
if (!component.Critical)
@@ -328,27 +328,51 @@ public void TakeStaminaDamage(EntityUid uid, float value, StaminaComponent? comp
}
}
+ public void ToggleStaminaDrain(EntityUid target, float drainRate, bool enabled, bool modifiesSpeed, EntityUid? source = null)
+ {
+ if (!TryComp(target, out var stamina))
+ return;
+
+ // If theres no source, we assume its the target that caused the drain.
+ var actualSource = source ?? target;
+
+ if (enabled)
+ {
+ stamina.ActiveDrains[actualSource] = (drainRate, modifiesSpeed);
+ EnsureComp(target);
+ }
+ else
+ stamina.ActiveDrains.Remove(actualSource);
+
+ Dirty(target, stamina);
+ }
+
public override void Update(float frameTime)
{
base.Update(frameTime);
-
if (!_timing.IsFirstTimePredicted)
return;
var stamQuery = GetEntityQuery();
var query = EntityQueryEnumerator();
var curTime = _timing.CurTime;
-
while (query.MoveNext(out var uid, out _))
{
// Just in case we have active but not stamina we'll check and account for it.
if (!stamQuery.TryGetComponent(uid, out var comp) ||
- comp.StaminaDamage <= 0f && !comp.Critical)
+ comp.StaminaDamage <= 0f && !comp.Critical && comp.ActiveDrains.Count == 0)
{
RemComp(uid);
continue;
}
-
+ if (comp.ActiveDrains.Count > 0)
+ foreach (var (source, (drainRate, modifiesSpeed)) in comp.ActiveDrains)
+ TakeStaminaDamage(uid,
+ drainRate * frameTime,
+ comp,
+ source: source,
+ visual: false,
+ allowsSlowdown: modifiesSpeed);
// Shouldn't need to consider paused time as we're only iterating non-paused stamina components.
var nextUpdate = comp.NextUpdate;
@@ -363,8 +387,11 @@ public override void Update(float frameTime)
}
comp.NextUpdate += TimeSpan.FromSeconds(1f);
- TakeStaminaDamage(uid, -comp.Decay, comp);
- Dirty(comp);
+ // If theres no active drains, recover stamina.
+ if (comp.ActiveDrains.Count == 0)
+ TakeStaminaDamage(uid, -comp.Decay, comp);
+
+ Dirty(uid, comp);
}
}
@@ -380,7 +407,6 @@ private void EnterStamCrit(EntityUid uid, StaminaComponent? component = null)
component.StaminaDamage = component.CritThreshold;
_stunSystem.TryParalyze(uid, component.StunTime, true);
-
// Give them buffer before being able to be re-stunned
component.NextUpdate = _timing.CurTime + component.StunTime + StamCritBufferTime;
EnsureComp(uid);
@@ -407,4 +433,4 @@ private void ExitStamCrit(EntityUid uid, StaminaComponent? component = null)
/// Raised before stamina damage is dealt to allow other systems to cancel it.
///
[ByRefEvent]
-public record struct BeforeStaminaDamageEvent(float Value, bool Cancelled = false);
+public record struct BeforeStaminaDamageEvent(float Value, bool Cancelled = false);
\ No newline at end of file
diff --git a/Content.Shared/Flight/Events.cs b/Content.Shared/Flight/Events.cs
new file mode 100644
index 0000000000..6666971b53
--- /dev/null
+++ b/Content.Shared/Flight/Events.cs
@@ -0,0 +1,24 @@
+using Robust.Shared.Serialization;
+using Content.Shared.DoAfter;
+
+namespace Content.Shared.Flight.Events;
+
+[Serializable, NetSerializable]
+public sealed partial class DashDoAfterEvent : SimpleDoAfterEvent { }
+
+[Serializable, NetSerializable]
+public sealed partial class FlightDoAfterEvent : SimpleDoAfterEvent { }
+
+[Serializable, NetSerializable]
+public sealed class FlightEvent : EntityEventArgs
+{
+ public NetEntity Uid { get; }
+ public bool IsFlying { get; }
+ public bool IsAnimated { get; }
+ public FlightEvent(NetEntity uid, bool isFlying, bool isAnimated)
+ {
+ Uid = uid;
+ IsFlying = isFlying;
+ IsAnimated = isAnimated;
+ }
+}
diff --git a/Content.Shared/Flight/FlightComponent.cs b/Content.Shared/Flight/FlightComponent.cs
new file mode 100644
index 0000000000..d250744544
--- /dev/null
+++ b/Content.Shared/Flight/FlightComponent.cs
@@ -0,0 +1,101 @@
+using Robust.Shared.Audio;
+using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
+
+namespace Content.Shared.Flight;
+
+///
+/// Adds an action that allows the user to become temporarily
+/// weightless at the cost of stamina and hand usage.
+///
+[RegisterComponent, NetworkedComponent(), AutoGenerateComponentState]
+public sealed partial class FlightComponent : Component
+{
+ [DataField(customTypeSerializer: typeof(PrototypeIdSerializer))]
+ public string? ToggleAction = "ActionToggleFlight";
+
+ [DataField, AutoNetworkedField]
+ public EntityUid? ToggleActionEntity;
+
+ ///
+ /// Is the user flying right now?
+ ///
+ [DataField, AutoNetworkedField]
+ public bool On;
+
+ ///
+ /// Stamina drain per second when flying
+ ///
+ [DataField, AutoNetworkedField]
+ public float StaminaDrainRate = 6.0f;
+
+ ///
+ /// DoAfter delay until the user becomes weightless.
+ ///
+ [DataField, AutoNetworkedField]
+ public float ActivationDelay = 1.0f;
+
+ ///
+ /// Speed modifier while in flight
+ ///
+ [DataField, AutoNetworkedField]
+ public float SpeedModifier = 2.0f;
+
+ ///
+ /// Path to a sound specifier or collection for the noises made during flight
+ ///
+ [DataField]
+ public SoundSpecifier FlapSound = new SoundCollectionSpecifier("WingFlaps");
+
+ ///
+ /// Is the flight animated?
+ ///
+ [DataField]
+ public bool IsAnimated = true;
+
+ ///
+ /// Does the animation animate a layer?.
+ ///
+ [DataField]
+ public bool IsLayerAnimated;
+
+ ///
+ /// Which RSI layer path does this animate?
+ ///
+ [DataField]
+ public string? Layer;
+
+ ///
+ /// Whats the speed of the shader?
+ ///
+ [DataField]
+ public float ShaderSpeed = 6.0f;
+
+ ///
+ /// How much are the values in the shader's calculations multiplied by?
+ ///
+ [DataField]
+ public float ShaderMultiplier = 0.01f;
+
+ ///
+ /// What is the offset on the shader?
+ ///
+ [DataField]
+ public float ShaderOffset = 0.25f;
+
+ ///
+ /// What animation does the flight use?
+ ///
+
+ [DataField]
+ public string AnimationKey = "default";
+
+ ///
+ /// Time between sounds being played
+ ///
+ [DataField]
+ public float FlapInterval = 1.0f;
+
+ public float TimeUntilFlap;
+}
diff --git a/Content.Shared/Flight/SharedFlightSystem.cs b/Content.Shared/Flight/SharedFlightSystem.cs
new file mode 100644
index 0000000000..281c6d70f0
--- /dev/null
+++ b/Content.Shared/Flight/SharedFlightSystem.cs
@@ -0,0 +1,104 @@
+using Content.Shared.Actions;
+using Content.Shared.Movement.Systems;
+using Content.Shared.Damage.Systems;
+using Content.Shared.Hands.Components;
+using Content.Shared.Hands.EntitySystems;
+using Content.Shared.Interaction.Components;
+using Content.Shared.Inventory.VirtualItem;
+using Content.Shared.Flight.Events;
+
+namespace Content.Shared.Flight;
+public abstract class SharedFlightSystem : EntitySystem
+{
+ [Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
+ [Dependency] private readonly SharedVirtualItemSystem _virtualItem = default!;
+ [Dependency] private readonly StaminaSystem _staminaSystem = default!;
+ [Dependency] private readonly SharedHandsSystem _hands = default!;
+ [Dependency] private readonly MovementSpeedModifierSystem _movementSpeed = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnStartup);
+ SubscribeLocalEvent(OnShutdown);
+ SubscribeLocalEvent(OnRefreshMoveSpeed);
+ }
+
+ #region Core Functions
+ private void OnStartup(EntityUid uid, FlightComponent component, ComponentStartup args)
+ {
+ _actionsSystem.AddAction(uid, ref component.ToggleActionEntity, component.ToggleAction);
+ }
+
+ private void OnShutdown(EntityUid uid, FlightComponent component, ComponentShutdown args)
+ {
+ _actionsSystem.RemoveAction(uid, component.ToggleActionEntity);
+ }
+
+ public void ToggleActive(EntityUid uid, bool active, FlightComponent component)
+ {
+ component.On = active;
+ component.TimeUntilFlap = 0f;
+ _actionsSystem.SetToggled(component.ToggleActionEntity, component.On);
+ RaiseNetworkEvent(new FlightEvent(GetNetEntity(uid), component.On, component.IsAnimated));
+ _staminaSystem.ToggleStaminaDrain(uid, component.StaminaDrainRate, active, false);
+ _movementSpeed.RefreshMovementSpeedModifiers(uid);
+ UpdateHands(uid, active);
+ Dirty(uid, component);
+ }
+
+ private void UpdateHands(EntityUid uid, bool flying)
+ {
+ if (!TryComp(uid, out var handsComponent))
+ return;
+
+ if (flying)
+ BlockHands(uid, handsComponent);
+ else
+ FreeHands(uid);
+ }
+
+ private void BlockHands(EntityUid uid, HandsComponent handsComponent)
+ {
+ var freeHands = 0;
+ foreach (var hand in _hands.EnumerateHands(uid, handsComponent))
+ {
+ if (hand.HeldEntity == null)
+ {
+ freeHands++;
+ continue;
+ }
+
+ // Is this entity removable? (they might have handcuffs on)
+ if (HasComp(hand.HeldEntity) && hand.HeldEntity != uid)
+ continue;
+
+ _hands.DoDrop(uid, hand, true, handsComponent);
+ freeHands++;
+ if (freeHands == 2)
+ break;
+ }
+ if (_virtualItem.TrySpawnVirtualItemInHand(uid, uid, out var virtItem1))
+ EnsureComp(virtItem1.Value);
+
+ if (_virtualItem.TrySpawnVirtualItemInHand(uid, uid, out var virtItem2))
+ EnsureComp(virtItem2.Value);
+ }
+
+ private void FreeHands(EntityUid uid)
+ {
+ _virtualItem.DeleteInHandsMatching(uid, uid);
+ }
+
+ private void OnRefreshMoveSpeed(EntityUid uid, FlightComponent component, RefreshMovementSpeedModifiersEvent args)
+ {
+ if (!component.On)
+ return;
+
+ args.ModifySpeed(component.SpeedModifier, component.SpeedModifier);
+ }
+
+ #endregion
+}
+public sealed partial class ToggleFlightEvent : InstantActionEvent { }
diff --git a/Content.Shared/Gravity/SharedFloatingVisualizerSystem.cs b/Content.Shared/Gravity/SharedFloatingVisualizerSystem.cs
index 57136116ca..8fe9e00e7e 100644
--- a/Content.Shared/Gravity/SharedFloatingVisualizerSystem.cs
+++ b/Content.Shared/Gravity/SharedFloatingVisualizerSystem.cs
@@ -1,5 +1,6 @@
using System.Numerics;
using Robust.Shared.Map;
+using Content.Shared.Flight.Events;
namespace Content.Shared.Gravity;
@@ -17,6 +18,7 @@ public override void Initialize()
SubscribeLocalEvent(OnComponentStartup);
SubscribeLocalEvent(OnGravityChanged);
SubscribeLocalEvent(OnEntParentChanged);
+ SubscribeNetworkEvent(OnFlight);
}
///
@@ -62,10 +64,24 @@ private void OnGravityChanged(ref GravityChangedEvent args)
}
}
+ private void OnFlight(FlightEvent args)
+ {
+ var uid = GetEntity(args.Uid);
+ if (!TryComp(uid, out var floating))
+ return;
+ floating.CanFloat = args.IsFlying;
+
+ if (!args.IsFlying
+ || !args.IsAnimated)
+ return;
+
+ FloatAnimation(uid, floating.Offset, floating.AnimationKey, floating.AnimationTime);
+ }
+
private void OnEntParentChanged(EntityUid uid, FloatingVisualsComponent component, ref EntParentChangedMessage args)
{
var transform = args.Transform;
if (CanFloat(uid, component, transform))
FloatAnimation(uid, component.Offset, component.AnimationKey, component.AnimationTime);
}
-}
+}
\ No newline at end of file
diff --git a/Content.Shared/Gravity/SharedGravitySystem.cs b/Content.Shared/Gravity/SharedGravitySystem.cs
index 100d2ee74f..55187bf14a 100644
--- a/Content.Shared/Gravity/SharedGravitySystem.cs
+++ b/Content.Shared/Gravity/SharedGravitySystem.cs
@@ -8,6 +8,7 @@
using Robust.Shared.Physics.Components;
using Robust.Shared.Serialization;
using Robust.Shared.Timing;
+using Content.Shared.Flight;
namespace Content.Shared.Gravity
{
@@ -24,6 +25,9 @@ public bool IsWeightless(EntityUid uid, PhysicsComponent? body = null, Transform
if ((body?.BodyType & (BodyType.Static | BodyType.Kinematic)) != 0)
return false;
+ if (TryComp(uid, out var flying) && flying.On)
+ return true;
+
if (TryComp(uid, out var ignoreGravityComponent))
return ignoreGravityComponent.Weightless;
@@ -142,4 +146,4 @@ public GravityComponentState(bool enabled)
}
}
}
-}
+}
\ No newline at end of file
diff --git a/Content.Shared/Medical/PenLightComponent.cs b/Content.Shared/Medical/PenLightComponent.cs
index 50dacae3dc..770e8af7e9 100644
--- a/Content.Shared/Medical/PenLightComponent.cs
+++ b/Content.Shared/Medical/PenLightComponent.cs
@@ -9,6 +9,7 @@ namespace Content.Shared.Medical;
[RegisterComponent, NetworkedComponent, AutoGenerateComponentPause]
public sealed partial class PenLightComponent : Component
{
+
///
/// Cooldown Time, exams take a bit
///
diff --git a/Content.Shared/Mood/MoodEffectPrototype.cs b/Content.Shared/Mood/MoodEffectPrototype.cs
index ad21faec80..ab9bca0160 100644
--- a/Content.Shared/Mood/MoodEffectPrototype.cs
+++ b/Content.Shared/Mood/MoodEffectPrototype.cs
@@ -12,24 +12,34 @@ public sealed class MoodEffectPrototype : IPrototype
public string ID { get; } = default!;
public string Description => Loc.GetString($"mood-effect-{ID}");
+
///
/// If they already have an effect with the same category, the new one will replace the old one.
///
[DataField, ValidatePrototypeId]
public string? Category;
+
///
/// How much should this moodlet modify an entity's Mood.
///
[DataField(required: true)]
public float MoodChange;
+
///
/// How long, in Seconds, does this moodlet last? If omitted, the moodlet will last until canceled by any system.
///
[DataField]
public int Timeout;
+
///
/// Should this moodlet be hidden from the player? EG: No popups or chat messages.
///
[DataField]
public bool Hidden;
+
+ ///
+ /// When not null, this moodlet will replace itself with another Moodlet upon expiration.
+ ///
+ [DataField]
+ public ProtoId? MoodletOnEnd;
}
diff --git a/Content.Shared/Movement/Components/InputMoverComponent.cs b/Content.Shared/Movement/Components/InputMoverComponent.cs
index 916ecc90af..40cb532e60 100644
--- a/Content.Shared/Movement/Components/InputMoverComponent.cs
+++ b/Content.Shared/Movement/Components/InputMoverComponent.cs
@@ -74,11 +74,12 @@ public sealed partial class InputMoverComponent : Component
public const float LerpTime = 1.0f;
- //NOTE I don't think I'm supposed to do this
- public bool Sprinting => IoCManager.Resolve().GetCVar(CCVars.GamePressToSprint)
+ public bool Sprinting => DefaultSprinting
? (HeldMoveButtons & MoveButtons.Walk) != 0x0
: (HeldMoveButtons & MoveButtons.Walk) == 0x0;
+ public bool DefaultSprinting = true;
+
[ViewVariables(VVAccess.ReadWrite)]
public bool CanMove = true;
@@ -94,6 +95,6 @@ public sealed class InputMoverComponentState : ComponentState
public Angle TargetRelativeRotation;
public Angle RelativeRotation;
public TimeSpan LerpTarget;
- public bool CanMove;
+ public bool CanMove, DefaultSprinting;
}
}
diff --git a/Content.Shared/Movement/Events/UpdateInputCVarsMessage.cs b/Content.Shared/Movement/Events/UpdateInputCVarsMessage.cs
new file mode 100644
index 0000000000..415a833f10
--- /dev/null
+++ b/Content.Shared/Movement/Events/UpdateInputCVarsMessage.cs
@@ -0,0 +1,9 @@
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Movement.Events;
+
+///
+/// Raised from the client to the server to require the server to update the client's input CVars.
+///
+[Serializable, NetSerializable]
+public sealed class UpdateInputCVarsMessage : EntityEventArgs { }
diff --git a/Content.Shared/Movement/Systems/SharedJetpackSystem.cs b/Content.Shared/Movement/Systems/SharedJetpackSystem.cs
index 8c42511f84..8d358f8db3 100644
--- a/Content.Shared/Movement/Systems/SharedJetpackSystem.cs
+++ b/Content.Shared/Movement/Systems/SharedJetpackSystem.cs
@@ -1,9 +1,11 @@
using Content.Shared.Actions;
+using Content.Shared.CCVar;
using Content.Shared.Gravity;
using Content.Shared.Interaction.Events;
using Content.Shared.Movement.Components;
using Content.Shared.Movement.Events;
using Content.Shared.Popups;
+using Robust.Shared.Configuration;
using Robust.Shared.Containers;
using Robust.Shared.Physics.Components;
using Robust.Shared.Physics.Systems;
@@ -20,6 +22,7 @@ public abstract class SharedJetpackSystem : EntitySystem
[Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
[Dependency] private readonly ActionContainerSystem _actionContainer = default!;
+ [Dependency] private readonly IConfigurationManager _config = default!;
public override void Initialize()
{
@@ -125,8 +128,11 @@ private void OnJetpackToggle(EntityUid uid, JetpackComponent component, ToggleJe
private bool CanEnableOnGrid(EntityUid? gridUid)
{
- return gridUid == null ||
- (!HasComp(gridUid));
+ return _config.GetCVar(CCVars.JetpackEnableAnywhere)
+ || gridUid == null
+ || _config.GetCVar(CCVars.JetpackEnableInNoGravity)
+ && TryComp(gridUid, out var comp)
+ && comp.Enabled;
}
private void OnJetpackGetAction(EntityUid uid, JetpackComponent component, GetItemActionsEvent args)
diff --git a/Content.Shared/Movement/Systems/SharedMoverController.CVars.cs b/Content.Shared/Movement/Systems/SharedMoverController.CVars.cs
new file mode 100644
index 0000000000..97c837eb8e
--- /dev/null
+++ b/Content.Shared/Movement/Systems/SharedMoverController.CVars.cs
@@ -0,0 +1,43 @@
+using Content.Shared.CCVar;
+using Content.Shared.Mind.Components;
+using Content.Shared.Movement.Components;
+using Content.Shared.Movement.Events;
+using Robust.Shared.Configuration;
+
+namespace Content.Shared.Movement.Systems;
+
+public abstract partial class SharedMoverController
+{
+ [Dependency] private readonly INetConfigurationManager _netConfig = default!;
+
+ private void InitializeCVars()
+ {
+ SubscribeLocalEvent(OnMindAdded);
+ SubscribeLocalEvent(OnMindRemoved);
+ SubscribeNetworkEvent(OnUpdateCVars);
+ }
+
+ private void OnMindAdded(Entity ent, ref MindAddedMessage args)
+ {
+ if (args.Mind.Comp.Session?.Channel is not { } channel)
+ return;
+
+ ent.Comp.DefaultSprinting = _netConfig.GetClientCVar(channel, CCVars.DefaultWalk);
+ WalkingAlert(ent, ent.Comp);
+ }
+
+ private void OnMindRemoved(Entity ent, ref MindRemovedMessage args)
+ {
+ // If it's an ai-controlled mob, we probably want them sprinting by default.
+ ent.Comp.DefaultSprinting = true;
+ }
+
+ private void OnUpdateCVars(UpdateInputCVarsMessage msg, EntitySessionEventArgs args)
+ {
+ if (args.SenderSession.AttachedEntity is not { } uid || !TryComp(uid, out var mover))
+ return;
+
+ mover.DefaultSprinting = _netConfig.GetClientCVar(args.SenderSession.Channel, CCVars.DefaultWalk);
+ WalkingAlert(uid, mover);
+ }
+}
diff --git a/Content.Shared/Movement/Systems/SharedMoverController.Input.cs b/Content.Shared/Movement/Systems/SharedMoverController.Input.cs
index 50cffa6ffe..d72ce6e2a2 100644
--- a/Content.Shared/Movement/Systems/SharedMoverController.Input.cs
+++ b/Content.Shared/Movement/Systems/SharedMoverController.Input.cs
@@ -5,6 +5,7 @@
using Content.Shared.Input;
using Content.Shared.Movement.Components;
using Content.Shared.Movement.Events;
+using Robust.Shared.Configuration;
using Robust.Shared.GameStates;
using Robust.Shared.Input;
using Robust.Shared.Input.Binding;
@@ -108,6 +109,7 @@ private void OnMoverHandleState(EntityUid uid, InputMoverComponent component, Co
component.TargetRelativeRotation = state.TargetRelativeRotation;
component.CanMove = state.CanMove;
component.RelativeEntity = EnsureEntity(state.RelativeEntity, uid);
+ component.DefaultSprinting = state.DefaultSprinting;
// Reset
component.LastInputTick = GameTick.Zero;
@@ -131,6 +133,7 @@ private void OnMoverGetState(EntityUid uid, InputMoverComponent component, ref C
HeldMoveButtons = component.HeldMoveButtons,
RelativeRotation = component.RelativeRotation,
TargetRelativeRotation = component.TargetRelativeRotation,
+ DefaultSprinting = component.DefaultSprinting
};
}
@@ -334,7 +337,7 @@ private void OnInputInit(EntityUid uid, InputMoverComponent component, Component
component.RelativeEntity = xform.GridUid ?? xform.MapUid;
component.TargetRelativeRotation = Angle.Zero;
- WalkingAlert(uid, !component.Sprinting);
+ WalkingAlert(uid, component);
}
private void HandleRunChange(EntityUid uid, ushort subTick, bool walking)
@@ -346,8 +349,8 @@ private void HandleRunChange(EntityUid uid, ushort subTick, bool walking)
// if we swap to relay then stop our existing input if we ever change back.
if (moverComp != null)
{
- WalkingAlert(uid, walking);
SetMoveInput(moverComp, MoveButtons.None);
+ WalkingAlert(uid, moverComp);
}
HandleRunChange(relayMover.RelayEntity, subTick, walking);
@@ -467,8 +470,8 @@ private void ResetSubtick(InputMoverComponent component)
public void SetSprinting(EntityUid entity, InputMoverComponent component, ushort subTick, bool walking)
{
// Logger.Info($"[{_gameTiming.CurTick}/{subTick}] Sprint: {enabled}");
- WalkingAlert(entity, walking);
SetMoveInput(entity, component, subTick, walking, MoveButtons.Walk);
+ WalkingAlert(entity, component);
}
///
@@ -620,7 +623,7 @@ public enum MoveButtons : byte
Down = 2,
Left = 4,
Right = 8,
- Walk = 16, // This may be either a sprint button or a walk button, depending on server config
+ Walk = 16, // This may be either a sprint button or a walk button, depending on mover config
AnyDirection = Up | Down | Left | Right,
}
diff --git a/Content.Shared/Movement/Systems/SharedMoverController.cs b/Content.Shared/Movement/Systems/SharedMoverController.cs
index 3cc35e7bc6..a3dc705ac1 100644
--- a/Content.Shared/Movement/Systems/SharedMoverController.cs
+++ b/Content.Shared/Movement/Systems/SharedMoverController.cs
@@ -98,6 +98,7 @@ public override void Initialize()
InitializeInput();
InitializeRelay();
+ InitializeCVars();
Subs.CVar(_configManager, CCVars.RelativeMovement, value => _relativeMovement = value, true);
Subs.CVar(_configManager, CCVars.StopSpeed, value => _stopSpeed = value, true);
UpdatesBefore.Add(typeof(TileFrictionController));
@@ -298,10 +299,9 @@ protected void HandleMobMovement(
PhysicsSystem.SetAngularVelocity(physicsUid, 0, body: physicsComponent);
}
- private void WalkingAlert(EntityUid player, bool walking)
+ private void WalkingAlert(EntityUid player, InputMoverComponent component)
{
- walking = _configManager.GetCVar(CCVars.GamePressToSprint) ? !walking : walking;
- _alerts.ShowAlert(player, AlertType.Walking, walking ? (short) 0 : (short) 1);
+ _alerts.ShowAlert(player, AlertType.Walking, component.Sprinting ? (short) 1 : (short) 0);
}
public void LerpRotation(EntityUid uid, InputMoverComponent mover, float frameTime)
diff --git a/Content.Shared/Nutrition/Components/ButcherableComponent.cs b/Content.Shared/Nutrition/Components/ButcherableComponent.cs
index 4fce45422a..975d4329dc 100644
--- a/Content.Shared/Nutrition/Components/ButcherableComponent.cs
+++ b/Content.Shared/Nutrition/Components/ButcherableComponent.cs
@@ -1,5 +1,6 @@
using Content.Shared.Storage;
using Robust.Shared.GameStates;
+using Robust.Shared.Serialization;
namespace Content.Shared.Nutrition.Components
{
@@ -25,6 +26,7 @@ public sealed partial class ButcherableComponent : Component
public bool BeingButchered;
}
+ [Serializable, NetSerializable]
public enum ButcheringType : byte
{
Knife, // e.g. goliaths
diff --git a/Content.Shared/Nutrition/EntitySystems/SharedFoodGuideDataSystem.cs b/Content.Shared/Nutrition/EntitySystems/SharedFoodGuideDataSystem.cs
new file mode 100644
index 0000000000..c31776cd75
--- /dev/null
+++ b/Content.Shared/Nutrition/EntitySystems/SharedFoodGuideDataSystem.cs
@@ -0,0 +1,158 @@
+using System.Linq;
+using Content.Shared.Chemistry.Reaction;
+using Content.Shared.Chemistry.Reagent;
+using Content.Shared.Kitchen;
+using Content.Shared.Nutrition.Components;
+using Content.Shared.Storage;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization;
+
+namespace Content.Client.Chemistry.EntitySystems;
+
+public abstract class SharedFoodGuideDataSystem : EntitySystem
+{
+ public List Registry = new();
+}
+
+[Serializable, NetSerializable]
+public sealed class FoodGuideRegistryChangedEvent : EntityEventArgs
+{
+ [DataField]
+ public List Changeset;
+
+ public FoodGuideRegistryChangedEvent(List changeset)
+ {
+ Changeset = changeset;
+ }
+}
+
+[DataDefinition, Serializable, NetSerializable]
+public partial struct FoodGuideEntry
+{
+ [DataField]
+ public EntProtoId Result;
+
+ [DataField]
+ public string Identifier; // Used for sorting
+
+ [DataField]
+ public FoodSourceData[] Sources;
+
+ [DataField]
+ public ReagentQuantity[] Composition;
+
+ public FoodGuideEntry(EntProtoId result, string identifier, FoodSourceData[] sources, ReagentQuantity[] composition)
+ {
+ Result = result;
+ Identifier = identifier;
+ Sources = sources;
+ Composition = composition;
+ }
+}
+
+[ImplicitDataDefinitionForInheritors, Serializable, NetSerializable]
+public abstract partial class FoodSourceData
+{
+ ///
+ /// Number of products created from this source. Used for primary ordering.
+ ///
+ public abstract int OutputCount { get; }
+
+ ///
+ /// A string used to distinguish different sources. Typically the name of the related entity.
+ ///
+ public string Identitier;
+
+ public abstract bool IsSourceOf(EntProtoId food);
+}
+
+[Serializable, NetSerializable]
+public sealed partial class FoodButcheringData : FoodSourceData
+{
+ [DataField]
+ public EntProtoId Butchered;
+
+ [DataField]
+ public ButcheringType Type;
+
+ [DataField]
+ public List Results;
+
+ public override int OutputCount => Results.Count;
+
+ public FoodButcheringData(EntityPrototype butchered, ButcherableComponent comp)
+ {
+ Identitier = butchered.Name;
+ Butchered = butchered.ID;
+ Type = comp.Type;
+ Results = comp.SpawnedEntities;
+ }
+
+ public override bool IsSourceOf(EntProtoId food) => Results.Any(it => it.PrototypeId == food);
+}
+
+[Serializable, NetSerializable]
+public sealed partial class FoodSlicingData : FoodSourceData
+{
+ [DataField]
+ public EntProtoId Sliced, Result;
+
+ [DataField]
+ private int _outputCount;
+ public override int OutputCount => _outputCount;
+
+ public FoodSlicingData(EntityPrototype sliced, EntProtoId result, int outputCount)
+ {
+ Identitier = sliced.Name;
+ Sliced = sliced.ID;
+ Result = result;
+ _outputCount = outputCount; // Server-only
+ }
+
+ public override bool IsSourceOf(EntProtoId food) => food == Result;
+}
+
+[Serializable, NetSerializable]
+public sealed partial class FoodRecipeData : FoodSourceData
+{
+ [DataField]
+ public ProtoId Recipe;
+
+ [DataField]
+ public EntProtoId Result;
+
+ public override int OutputCount => 1;
+
+ public FoodRecipeData(FoodRecipePrototype proto)
+ {
+ Identitier = proto.Name;
+ Recipe = proto.ID;
+ Result = proto.Result;
+ }
+
+ public override bool IsSourceOf(EntProtoId food) => food == Result;
+}
+
+[Serializable, NetSerializable]
+public sealed partial class FoodReactionData : FoodSourceData
+{
+ [DataField]
+ public ProtoId Reaction;
+
+ [DataField]
+ public EntProtoId Result;
+
+ [DataField]
+ private int _outputCount;
+ public override int OutputCount => _outputCount;
+
+ public FoodReactionData(ReactionPrototype reaction, EntProtoId result, int outputCount)
+ {
+ Identitier = reaction.Name;
+ Reaction = reaction.ID;
+ Result = result;
+ _outputCount = outputCount;
+ }
+
+ public override bool IsSourceOf(EntProtoId food) => food == Result;
+}
diff --git a/Content.Shared/Traits/Prototypes/TraitPrototype.cs b/Content.Shared/Traits/Prototypes/TraitPrototype.cs
index 7bdff058ee..cd4b02a1e6 100644
--- a/Content.Shared/Traits/Prototypes/TraitPrototype.cs
+++ b/Content.Shared/Traits/Prototypes/TraitPrototype.cs
@@ -1,4 +1,5 @@
using Content.Shared.Customization.Systems;
+using Content.Shared.Mood;
using Content.Shared.Psionics;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
@@ -56,4 +57,10 @@ public sealed partial class TraitPrototype : IPrototype
///
[DataField]
public List? PsionicPowers { get; private set; } = default!;
+
+ ///
+ /// The list of all Moodlets that this trait adds.
+ ///
+ [DataField]
+ public List>? MoodEffects { get; private set; } = default!;
}
diff --git a/Resources/Audio/Effects/Flight/wingflap1.ogg b/Resources/Audio/Effects/Flight/wingflap1.ogg
new file mode 100644
index 0000000000..724ac3ecd2
Binary files /dev/null and b/Resources/Audio/Effects/Flight/wingflap1.ogg differ
diff --git a/Resources/Audio/Effects/Flight/wingflap2.ogg b/Resources/Audio/Effects/Flight/wingflap2.ogg
new file mode 100644
index 0000000000..b0264a1317
Binary files /dev/null and b/Resources/Audio/Effects/Flight/wingflap2.ogg differ
diff --git a/Resources/Audio/Effects/Flight/wingflap3.ogg b/Resources/Audio/Effects/Flight/wingflap3.ogg
new file mode 100644
index 0000000000..aeb0e21acf
Binary files /dev/null and b/Resources/Audio/Effects/Flight/wingflap3.ogg differ
diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml
index d7068562a8..6a8111cec5 100644
--- a/Resources/Changelog/Changelog.yml
+++ b/Resources/Changelog/Changelog.yml
@@ -6130,3 +6130,254 @@ Entries:
id: 6340
time: '2024-09-09T14:21:56.0000000+00:00'
url: https://github.com/Simple-Station/Einstein-Engines/pull/794
+- author: Mnemotechnician
+ changes:
+ - type: Add
+ message: >-
+ The "food recipes" page in guidebook now contains an automatically
+ generated list of food recipes.
+ id: 6341
+ time: '2024-09-11T17:55:11.0000000+00:00'
+ url: https://github.com/Simple-Station/Einstein-Engines/pull/783
+- author: VMSolidus
+ changes:
+ - type: Add
+ message: Rat Kings have returned to the default event rotation.
+ id: 6342
+ time: '2024-09-11T19:59:32.0000000+00:00'
+ url: https://github.com/Simple-Station/Einstein-Engines/pull/903
+- author: VMSolidus
+ changes:
+ - type: Add
+ message: Jetpacks now work in zero gravity.
+ - type: Add
+ message: >-
+ New CCVar "jetpack.enable_anywhere" allows server hosts to optionally
+ make it so that jetpacks can be used anywhere, even in gravity and on
+ grids.
+ - type: Add
+ message: >-
+ New CCVar "jetpack.enable_in_no_gravity" allows server hosts to
+ optionally disable jetpacks being usable in zero gravity.
+ id: 6343
+ time: '2024-09-11T19:59:45.0000000+00:00'
+ url: https://github.com/Simple-Station/Einstein-Engines/pull/901
+- author: VMSolidus
+ changes:
+ - type: Add
+ message: >-
+ Medical Job related items are now part of a Medical loadout group, and
+ have all been significantly discounted.
+ id: 6344
+ time: '2024-09-11T20:00:07.0000000+00:00'
+ url: https://github.com/Simple-Station/Einstein-Engines/pull/902
+- author: Tilkku
+ changes:
+ - type: Tweak
+ message: Penlight Exam Messages
+ - type: Fix
+ message: Penlights now need to be on in order to examine
+ - type: Fix
+ message: Penlights can no longer be used on self
+ id: 6345
+ time: '2024-09-11T20:02:51.0000000+00:00'
+ url: https://github.com/Simple-Station/Einstein-Engines/pull/900
+- author: Mnemotechnician
+ changes:
+ - type: Fix
+ message: Fixed a couple issues with the language menu UI and translators.
+ id: 6346
+ time: '2024-09-11T20:03:25.0000000+00:00'
+ url: https://github.com/Simple-Station/Einstein-Engines/pull/893
+- author: Mocho
+ changes:
+ - type: Add
+ message: >-
+ Cargo Job related items are now part of a Cargo loadout group, and have
+ all been significantly discounted.
+ id: 6347
+ time: '2024-09-11T20:27:13.0000000+00:00'
+ url: https://github.com/Simple-Station/Einstein-Engines/pull/909
+- author: Mocho
+ changes:
+ - type: Add
+ message: >-
+ Security Job related items are now part of a Security loadout group, and
+ have all been significantly discounted.
+ id: 6348
+ time: '2024-09-11T20:39:55.0000000+00:00'
+ url: https://github.com/Simple-Station/Einstein-Engines/pull/908
+- author: Mocho
+ changes:
+ - type: Add
+ message: >-
+ Service Job related items are now part of a Service loadout group, and
+ have all been significantly discounted.
+ - type: Tweak
+ message: >-
+ Musicians now have significant discounts on all instruments in loadouts,
+ but can only take a maximum of 3.
+ id: 6349
+ time: '2024-09-11T20:52:21.0000000+00:00'
+ url: https://github.com/Simple-Station/Einstein-Engines/pull/906
+- author: Mocho
+ changes:
+ - type: Add
+ message: >-
+ Engineering Job related items are now part of a Engineering loadout
+ group, and have all been significantly discounted.
+ id: 6350
+ time: '2024-09-11T21:03:37.0000000+00:00'
+ url: https://github.com/Simple-Station/Einstein-Engines/pull/907
+- author: Squishy77
+ changes:
+ - type: Add
+ message: >-
+ added rcds to the list of possible re and ported over the re update from
+ delta
+ - type: Tweak
+ message: >-
+ tweaked the costs of boards re-machine boards to be more consistent with
+ their post hyper lathe update counter parts
+ id: 6351
+ time: '2024-09-12T00:12:39.0000000+00:00'
+ url: https://github.com/Simple-Station/Einstein-Engines/pull/910
+- author: SleepyScarecrow
+ changes:
+ - type: Tweak
+ message: Ethanol Contents
+ - type: Fix
+ message: SnowWhite Recipe
+ - type: Tweak
+ message: Ethanol overdose changed from 15 to 45
+ id: 6352
+ time: '2024-09-12T00:14:06.0000000+00:00'
+ url: https://github.com/Simple-Station/Einstein-Engines/pull/911
+- author: Mnemotechnician
+ changes:
+ - type: Add
+ message: Ported a number of jukebox songs from Delta-V.
+ id: 6353
+ time: '2024-09-12T00:14:56.0000000+00:00'
+ url: https://github.com/Simple-Station/Einstein-Engines/pull/912
+- author: Skubman
+ changes:
+ - type: Fix
+ message: >-
+ Blood Deficiency now makes you lose a consistent percentage of blood
+ regardless of your blood volume, which is dictated by size. This makes
+ the time to low blood and death consistent for every character of all
+ sizes with this trait.
+ id: 6354
+ time: '2024-09-12T00:15:18.0000000+00:00'
+ url: https://github.com/Simple-Station/Einstein-Engines/pull/895
+- author: stellar-novas
+ changes:
+ - type: Add
+ message: Airlocks once again have access wires. Happy hacking!
+ id: 6355
+ time: '2024-09-14T00:48:34.0000000+00:00'
+ url: https://github.com/Simple-Station/Einstein-Engines/pull/916
+- author: Mocho
+ changes:
+ - type: Add
+ message: >-
+ Science Job related items are now part of a Science loadout group, and
+ have all been significantly discounted.
+ - type: Add
+ message: Added more clothing to the science section in loadouts.
+ - type: Tweak
+ message: Adjusted command loadout item pricing.
+ - type: Tweak
+ message: Added localization strings for the new loadout groups.
+ id: 6356
+ time: '2024-09-14T01:00:26.0000000+00:00'
+ url: https://github.com/Simple-Station/Einstein-Engines/pull/914
+- author: VMSolidus
+ changes:
+ - type: Add
+ message: >-
+ Added missing Localizations for Departments, Jobs, and Loadout Item
+ Groups.
+ - type: Add
+ message: >-
+ Bartender-Specific loadouts! Bartenders can now choose to spawn with
+ either their classic shotgun, or a Mosin Nagant that comes preloaded
+ with rubber bullets.
+ id: 6357
+ time: '2024-09-14T01:12:40.0000000+00:00'
+ url: https://github.com/Simple-Station/Einstein-Engines/pull/915
+- author: CilliePaint
+ changes:
+ - type: Tweak
+ message: Stuffed Lawyer's Pockets with Space Law guides!
+ - type: Remove
+ message: Took away Atmos backpacks as Starting equipment.
+ id: 6358
+ time: '2024-09-14T05:41:40.0000000+00:00'
+ url: https://github.com/Simple-Station/Einstein-Engines/pull/897
+- author: Mnemotechnician
+ changes:
+ - type: Add
+ message: >-
+ You can now choose whether you want to walk or run by default in the
+ settings.
+ id: 6359
+ time: '2024-09-14T05:44:56.0000000+00:00'
+ url: https://github.com/Simple-Station/Einstein-Engines/pull/889
+- author: VMSolidus
+ changes:
+ - type: Add
+ message: >-
+ Drug Addictions! Drug addictions are long lasting Moodlet-Pairs. The
+ first consisting of a temporary Mood bonus that is refreshed by
+ consuming the drug, and the second consisting of an extremely long
+ lasting mood penalty, which replaces the mood bonus should you go a long
+ enough time between consuming the drug in question.
+ - type: Add
+ message: Nicotine Addiction has been added as a new minor negative trait.
+ - type: Add
+ message: >-
+ Drugs/Reagents can now affect your character's Mood! Both with, and
+ without Addiction.
+ - type: Add
+ message: >-
+ TraitSystem has had functionality added for directly adding Moodlets to
+ a character upon joining the round, such as drug addictions, or
+ permanent mood modifications like Sanguine/Saturnine
+ - type: Add
+ message: >-
+ Lotophagoi Oil now induces an extremely powerful drug addiction,
+ providing an extremely large mood benefit for a short time. Which when
+ it wears off, creates an equally extreme mood penalty that lasts for a
+ very long time(or until you drink more Loto Oil).
+ id: 6360
+ time: '2024-09-14T06:48:55.0000000+00:00'
+ url: https://github.com/Simple-Station/Einstein-Engines/pull/896
+- author: Mnemotechnician
+ changes:
+ - type: Fix
+ message: Cyborg recharging stations finally work again.
+ - type: Fix
+ message: >-
+ Rehydratable entities (such as monkey cubes) no longer spawn a second
+ client-side entity when rehydrated.
+ id: 6361
+ time: '2024-09-14T17:55:41.0000000+00:00'
+ url: https://github.com/Simple-Station/Einstein-Engines/pull/888
+- author: VMSolidus
+ changes:
+ - type: Tweak
+ message: The Uncloneable trait is only worth one point now.
+ id: 6362
+ time: '2024-09-14T18:01:21.0000000+00:00'
+ url: https://github.com/Simple-Station/Einstein-Engines/pull/868
+- author: Mocho
+ changes:
+ - type: Add
+ message: >-
+ Harpies are now able to fly on station for limited periods of time,
+ moving faster at the cost of stamina.
+ id: 6363
+ time: '2024-09-16T04:41:44.0000000+00:00'
+ url: https://github.com/Simple-Station/Einstein-Engines/pull/919
diff --git a/Resources/Locale/en-US/cuffs/components/handcuff-component.ftl b/Resources/Locale/en-US/cuffs/components/handcuff-component.ftl
index 16447f4251..1f8a895164 100644
--- a/Resources/Locale/en-US/cuffs/components/handcuff-component.ftl
+++ b/Resources/Locale/en-US/cuffs/components/handcuff-component.ftl
@@ -3,6 +3,7 @@ handcuff-component-cuffs-broken-error = The restraints are broken!
handcuff-component-target-has-no-hands-error = {$targetName} has no hands!
handcuff-component-target-has-no-free-hands-error = {$targetName} has no free hands!
handcuff-component-too-far-away-error = You are too far away to use the restraints!
+handcuff-component-target-flying-error = You cannot reach {$targetName}'s hands!
handcuff-component-start-cuffing-observer = {$user} starts restraining {$target}!
handcuff-component-start-cuffing-target-message = You start restraining {$targetName}.
handcuff-component-start-cuffing-by-other-message = {$otherName} starts restraining you!
diff --git a/Resources/Locale/en-US/escape-menu/ui/options-menu.ftl b/Resources/Locale/en-US/escape-menu/ui/options-menu.ftl
index 2eab749c35..7d6af11f37 100644
--- a/Resources/Locale/en-US/escape-menu/ui/options-menu.ftl
+++ b/Resources/Locale/en-US/escape-menu/ui/options-menu.ftl
@@ -115,6 +115,7 @@ ui-options-header-general = General
ui-options-hotkey-keymap = Use US QWERTY Keys
ui-options-hotkey-toggle-walk = Toggle Speed
+ui-options-hotkey-default-walk = Walk by default
ui-options-function-move-up = Move Up
ui-options-function-move-left = Move Left
diff --git a/Resources/Locale/en-US/flight/flight_system.ftl b/Resources/Locale/en-US/flight/flight_system.ftl
new file mode 100644
index 0000000000..12693cc846
--- /dev/null
+++ b/Resources/Locale/en-US/flight/flight_system.ftl
@@ -0,0 +1,2 @@
+no-flight-while-restrained = You can't fly right now.
+no-flight-while-zombified = You can't use your wings right now.
\ No newline at end of file
diff --git a/Resources/Locale/en-US/guidebook/chemistry/effects.ftl b/Resources/Locale/en-US/guidebook/chemistry/effects.ftl
index db2f3816f6..dbb24a3caf 100644
--- a/Resources/Locale/en-US/guidebook/chemistry/effects.ftl
+++ b/Resources/Locale/en-US/guidebook/chemistry/effects.ftl
@@ -361,4 +361,11 @@ reagent-effect-guidebook-chem-reroll-psionic =
{ $chance ->
[1] Allows
*[other] allow
- } a chance to get a different psionic power
\ No newline at end of file
+ } a chance to get a different psionic power
+
+reagent-effect-guidebook-add-moodlet =
+ modifies mood by {$amount}
+ { $timeout ->
+ [0] indefinitely
+ *[other] for {$timeout} seconds
+ }
\ No newline at end of file
diff --git a/Resources/Locale/en-US/guidebook/food.ftl b/Resources/Locale/en-US/guidebook/food.ftl
new file mode 100644
index 0000000000..bd4fa03251
--- /dev/null
+++ b/Resources/Locale/en-US/guidebook/food.ftl
@@ -0,0 +1,16 @@
+guidebook-food-name = [bold][color={$color}]{CAPITALIZE($name)}[/color][/bold]
+guidebook-food-unknown-proto = Unknown prototype
+guidebook-food-sources-header = Sources
+guidebook-food-sources-ent-wrapper = {$name}
+guidebook-food-reagents-header = Chemical composition
+
+guidebook-food-processing-butchering = Butcher
+guidebook-food-processing-slicing = Slice
+guidebook-food-processing-cooking = Microwave for {$time}s
+guidebook-food-processing-reaction = Mix
+
+guidebook-food-processing-recipe = {$ingredients}
+guidebook-food-ingredient-solid = add {$amount} {$name}
+guidebook-food-ingredient-liquid = add {$amount}u {$name}
+
+guidebook-food-output = {$name} ({$number})
diff --git a/Resources/Locale/en-US/loadouts/categories.ftl b/Resources/Locale/en-US/loadouts/categories.ftl
index 6dde7128d8..9a3291ed8a 100644
--- a/Resources/Locale/en-US/loadouts/categories.ftl
+++ b/Resources/Locale/en-US/loadouts/categories.ftl
@@ -8,6 +8,7 @@ loadout-category-Head = Head
loadout-category-Items = Items
loadout-category-Jobs = Jobs
loadout-category-JobsAUncategorized = Uncategorized
+loadout-category-JobsCargo = Logistics
loadout-category-JobsCommand = Command
loadout-category-JobsCommandAUncategorized = Uncategorized
loadout-category-JobsCommandCaptain = Captain
@@ -17,6 +18,13 @@ loadout-category-JobsCommandHOP = Head of Personnel
loadout-category-JobsCommandHOS = Head of Security
loadout-category-JobsCommandQM = Logistics Officer
loadout-category-JobsCommandRD = Mystagogue
+loadout-category-JobsEngineering = Engineering
+loadout-category-JobsMedical = Medical
+loadout-category-JobsScience = Epistemics
+loadout-category-JobsSecurity = Security
+loadout-category-JobsService = Service
+loadout-category-JobsServiceUncategorized = Uncategorized
+loadout-category-JobsServiceBartender = Bartender
loadout-category-Mask = Mask
loadout-category-Neck = Neck
loadout-category-Outer = Outer
diff --git a/Resources/Locale/en-US/loadouts/itemgroups.ftl b/Resources/Locale/en-US/loadouts/itemgroups.ftl
new file mode 100644
index 0000000000..29aca3ddb9
--- /dev/null
+++ b/Resources/Locale/en-US/loadouts/itemgroups.ftl
@@ -0,0 +1,66 @@
+# This list is sorted Mixed Alphabetically with Generic always being placed first, Departments alphabetically, Items Groups Alphabetically, and Jobs Alphabetically after all Department items
+# Generic - Clothing
+character-item-group-LoadoutEyes = Civilian Eyewear
+character-item-group-LoadoutGloves = Civilian Gloves
+character-item-group-LoadoutHead = Civilian Headgear
+character-item-group-LoadoutMasks = Civilian Masks
+character-item-group-LoadoutNeck = Civilian Neckwear
+character-item-group-LoadoutOuter = Civilian Outerwear
+character-item-group-LoadoutShoes = Civilian Shoes
+character-item-group-LoadoutUniformsCivilian = Civilian Uniforms
+
+# Generic - Items
+character-item-group-LoadoutAirTank = Emergency Air Tanks
+character-item-group-LoadoutLighters = Lighters
+character-item-group-LoadoutInstrumentsAny = Musical Instruments (Non-Musician)
+character-item-group-LoadoutSmokes = Smokeables
+character-item-group-LoadoutBoxKits = Survival Kits
+character-item-group-LoadoutWritables = Writing Tools
+
+# Cargo
+character-item-group-LoadoutNeckCargo = Logistics Neckwear
+character-item-group-LoadoutOuterCargo = Logistics Outerwear
+character-item-group-LoadoutShoesCargo = Logistics Shoes
+
+# Engineering
+character-item-group-LoadoutEyesEngineering = Engineering Eyewear
+character-item-group-LoadoutHeadEngineering = Engineering Headgear
+character-item-group-LoadoutOuterEngineering = Engineering Outerwear
+character-item-group-LoadoutUniformsEngineering = Engineering Uniforms
+
+# Medical
+character-item-group-LoadoutEyesMedical = Medical Eyewear
+character-item-group-LoadoutGlovesMedical = Medical Gloves
+character-item-group-LoadoutHeadMedical = Medical Headgear
+character-item-group-LoadoutNeckMedical = Medical Neckwear
+character-item-group-LoadoutOuterMedical = Medical Outerwear
+character-item-group-LoadoutShoesMedical = Medical Shoes
+character-item-group-LoadoutUniformsMedical = Medical Uniforms
+
+# Security
+character-item-group-LoadoutBeltSecurity = Security Belts
+character-item-group-LoadoutEquipmentSecurity = Security Equipment
+character-item-group-LoadoutEyesSecurity = Security Eyewear
+character-item-group-LoadoutGlovesSecurity = Security Gloves
+character-item-group-LoadoutHeadSecurity = Security Headgear
+character-item-group-LoadoutMaskSecurity = Security Masks
+character-item-group-LoadoutNeckSecurity = Security Neckwear
+character-item-group-LoadoutOuterSecurity = Security Outerwear
+character-item-group-LoadoutShoesSecurity = Security Shoes
+character-item-group-LoadoutUniformsSecurity = Security Uniforms
+
+# Service
+character-item-group-LoadoutEquipmentService = Service Equipment
+character-item-group-LoadoutMaskService = Service Masks
+character-item-group-LoadoutNeckService = Service Neckwear
+character-item-group-LoadoutOuterService = Service Outerwear
+character-item-group-LoadoutShoesService = Service Shoes
+character-item-group-LoadoutUniformsService = Service Uniforms
+
+# Service - Bartender
+character-item-group-LoadoutBartenderAmmo = Bartender Ammo
+character-item-group-LoadoutBartenderOuterwear = Bartender Outerwear
+character-item-group-LoadoutBartenderWeapon = Bartender Weapon
+
+# Service - Musician
+character-item-group-LoadoutMusicianInstruments = Musician Instruments
diff --git a/Resources/Locale/en-US/medical/components/penlight.ftl b/Resources/Locale/en-US/medical/components/penlight.ftl
index f0639ad738..c8a5d66f5d 100644
--- a/Resources/Locale/en-US/medical/components/penlight.ftl
+++ b/Resources/Locale/en-US/medical/components/penlight.ftl
@@ -1,11 +1,12 @@
penlight-off = The pen light is off.
+penlight-cannot-examine-self = You cannot examine your own eyes.
pen-light-exam-title = Pen Light
pen-light-window-entity-eyes-text = {$entityName}'s conditions:
pen-light-window-no-patient-data-text = No patient data.
pen-light-window-entity-unknown-text = unknown
pen-light-exam-blind-text = The patient's eyes are glassy and unfocused. They can't follow the light at all.
-pen-light-exam-drunk-text = The patient's eyes are slow to follow the light, droopy.
-pen-light-exam-eyedamage-text = The patient's eyes are partially focused, though they struggle to look at the light for too long.
+pen-light-exam-drunk-text = There's a clear delay between moving the light and the patient's eyes following.
+pen-light-exam-eyedamage-text = The patient's eyes have dark spots within the pupil, evident when the light is shone in them.
pen-light-exam-hallucinating-text = The patient's eyes are wandering around, with dilated pupils. They don't focus on the light.
pen-light-exam-healthy-text = The patient follows the light perfectly with no stuttering.
\ No newline at end of file
diff --git a/Resources/Locale/en-US/mood/mood.ftl b/Resources/Locale/en-US/mood/mood.ftl
index bd64d52582..a931a30fb3 100644
--- a/Resources/Locale/en-US/mood/mood.ftl
+++ b/Resources/Locale/en-US/mood/mood.ftl
@@ -54,3 +54,16 @@ mood-effect-RevolutionFocused = VIVA LA REVOLUTION!!!
mood-effect-CultFocused = Dark Gods, grant me strength!
mood-effect-TraitSanguine = I have nothing to worry about. I'm sure everything will turn out well in the end!
+
+# Addictions
+mood-effect-LotoTranscendence =
+ I CAN SEE ALL THAT IS, ALL THAT WILL EVER BE, AND ALL THAT EVER WAS. ALL OF CREATION HAS OPENED TO MY MIND!
+ I MUST HAVE IT ALL. I MUST KNOW IT ALL. ALL OF IT. FOREVER!
+mood-effect-LotoEnthrallment =
+ It has fled from me... The heart of all creation is gone from my soul, leaving behind an emptiness I cannot bear.
+ I fear that I will wither to nothing if I cannot drink from the cup of knowledge once again.
+
+mood-effect-NicotineBenefit =
+ I feel as if I have been standing my entire life and I just sat down.
+mood-effect-NicotineWithdrawal =
+ I could really go for a smoke right now.
\ No newline at end of file
diff --git a/Resources/Locale/en-US/traits/traits.ftl b/Resources/Locale/en-US/traits/traits.ftl
index e049af3c62..ff329a12a7 100644
--- a/Resources/Locale/en-US/traits/traits.ftl
+++ b/Resources/Locale/en-US/traits/traits.ftl
@@ -227,3 +227,7 @@ trait-description-AnomalousPositronics =
Whether by intentional design from the manufacturer, black market modifications, or accidental omission,
your positronic brain lacks its standard psionic insulation. As a being that can be argued to have a soul,
this by extension means that it is possible for you to be influenced by the Noosphere.
+
+trait-name-AddictionNicotine = Nicotine Addiction
+trait-description-AddictionNicotine =
+ You have an addiction to Nicotine, and will require frequent smoke breaks to keep your mood in check.
\ No newline at end of file
diff --git a/Resources/Prototypes/Catalog/Fills/Lockers/service.yml b/Resources/Prototypes/Catalog/Fills/Lockers/service.yml
index b86fa2e1f5..83bbdb435f 100644
--- a/Resources/Prototypes/Catalog/Fills/Lockers/service.yml
+++ b/Resources/Prototypes/Catalog/Fills/Lockers/service.yml
@@ -5,8 +5,6 @@
components:
- type: StorageFill
contents:
- - id: ClothingOuterArmorDuraVest # DeltaV - ClothingOuterArmorBasicSlim replaced in favour of stabproof vest
- - id: WeaponShotgunDoubleBarreledRubber
- id: DrinkShaker
- id: ClothingEyesHudBeer
- id: HandLabeler
@@ -17,8 +15,6 @@
prob: 0.5
- id: DrinkBottleBeer
prob: 0.5
- - id: BoxBeanbag
- amount: 2
- id: RagItem
amount: 2
- id: LunchboxServiceFilledRandom # Delta-V Lunchboxes!
diff --git a/Resources/Prototypes/CharacterItemGroups/cargoGroups.yml b/Resources/Prototypes/CharacterItemGroups/cargoGroups.yml
new file mode 100644
index 0000000000..6b12652b33
--- /dev/null
+++ b/Resources/Prototypes/CharacterItemGroups/cargoGroups.yml
@@ -0,0 +1,19 @@
+- type: characterItemGroup
+ id: LoadoutOuterCargo
+ items:
+ - type: loadout
+ id: LoadoutCargoOuterWinterCargo
+ - type: loadout
+ id: LoadoutCargoOuterWinterMiner
+
+- type: characterItemGroup
+ id: LoadoutNeckCargo
+ items:
+ - type: loadout
+ id: LoadoutCargoNeckGoliathCloak
+
+- type: characterItemGroup
+ id: LoadoutShoesCargo
+ items:
+ - type: loadout
+ id: LoadoutCargoShoesBootsWinterCargo
diff --git a/Resources/Prototypes/CharacterItemGroups/engineeringGroups.yml b/Resources/Prototypes/CharacterItemGroups/engineeringGroups.yml
new file mode 100644
index 0000000000..6db873cecf
--- /dev/null
+++ b/Resources/Prototypes/CharacterItemGroups/engineeringGroups.yml
@@ -0,0 +1,39 @@
+- type: characterItemGroup
+ id: LoadoutUniformsEngineering
+ items:
+ - type: loadout
+ id: LoadoutEngineeringUniformHazard
+ - type: loadout
+ id: LoadoutEngineeringUniformJumpskirtSenior
+ - type: loadout
+ id: LoadoutEngineeringUniformJumpsuitSenior
+
+- type: characterItemGroup
+ id: LoadoutOuterEngineering
+ items:
+ - type: loadout
+ id: LoadoutEngineeringOuterHazard
+ - type: loadout
+ id: LoadoutEngineeringChickenSuit
+
+- type: characterItemGroup
+ id: LoadoutHeadEngineering
+ items:
+ - type: loadout
+ id: LoadoutEngineeringHeadBeret
+ - type: loadout
+ id: LoadoutEngineeringHeadHardhatBlue
+ - type: loadout
+ id: LoadoutEngineeringHeadHardhatOrange
+ - type: loadout
+ id: LoadoutEngineeringHeadHardhatRed
+ - type: loadout
+ id: LoadoutEngineeringHeadHardhatWhite
+ - type: loadout
+ id: LoadoutEngineeringHeadHardhatYellow
+
+- type: characterItemGroup
+ id: LoadoutEyesEngineering
+ items:
+ - type: loadout
+ id: LoadoutEngineeringEyesMeson
\ No newline at end of file
diff --git a/Resources/Prototypes/CharacterItemGroups/medicalGroups.yml b/Resources/Prototypes/CharacterItemGroups/medicalGroups.yml
new file mode 100644
index 0000000000..396f07290f
--- /dev/null
+++ b/Resources/Prototypes/CharacterItemGroups/medicalGroups.yml
@@ -0,0 +1,101 @@
+- type: characterItemGroup
+ id: LoadoutUniformsMedical
+ items:
+ - type: loadout
+ id: LoadoutMedicalUniformScrubsBlue
+ - type: loadout
+ id: LoadoutMedicalUniformScrubsGreen
+ - type: loadout
+ id: LoadoutMedicalUniformScrubsPurple
+ - type: loadout
+ id: LoadoutMedicalUniformScrubsCyan
+ - type: loadout
+ id: LoadoutMedicalUniformScrubsBlack
+ - type: loadout
+ id: LoadoutMedicalUniformScrubsPink
+ - type: loadout
+ id: LoadoutMedicalUniformScrubsCybersun
+ - type: loadout
+ id: LoadoutMedicalUniformParamedicJumpsuit
+ - type: loadout
+ id: LoadoutMedicalUniformParamedicJumpskirt
+ - type: loadout
+ id: LoadoutMedicalUniformJumpskirtSenior
+ - type: loadout
+ id: LoadoutMedicalUniformJumpsuitSenior
+ - type: loadout
+ id: LoadoutMedicalUniformJumpsuitChemShirt
+
+- type: characterItemGroup
+ id: LoadoutOuterMedical
+ items:
+ - type: loadout
+ id: LoadoutMedicalOuterLabcoat
+ - type: loadout
+ id: LoadoutMedicalOuterCybersunWindbreaker
+ - type: loadout
+ id: LoadoutMedicalOuterLabcoatChem
+ - type: loadout
+ id: LoadoutMedicalOuterApronChemist
+
+- type: characterItemGroup
+ id: LoadoutGlovesMedical
+ items:
+ - type: loadout
+ id: LoadoutMedicalGlovesNitrile
+ - type: loadout
+ id: LoadoutMedicalHandsGlovesChemist
+
+- type: characterItemGroup
+ id: LoadoutNeckMedical
+ items:
+ - type: loadout
+ id: LoadoutMedicalNeckStethoscope
+ - type: loadout
+ id: LoadoutMedicalBedsheetMedical
+ - type: loadout
+ id: LoadoutMedicalNeckTieChem
+
+- type: characterItemGroup
+ id: LoadoutHeadMedical
+ items:
+ - type: loadout
+ id: LoadoutMedicalHeadNurse
+ - type: loadout
+ id: LoadoutMedicalHeadBeretSeniorPhysician
+ - type: loadout
+ id: LoadoutMedicalHeadSurgcapBlue
+ - type: loadout
+ id: LoadoutMedicalHeadSurgcapPurple
+ - type: loadout
+ id: LoadoutMedicalHeadSurgcapGreen
+ - type: loadout
+ id: LoadoutMedicalHeadSurgcapCyan
+ - type: loadout
+ id: LoadoutMedicalHeadSurgcapBlack
+ - type: loadout
+ id: LoadoutMedicalHeadSurgcapPink
+ - type: loadout
+ id: LoadoutMedicalHeadSurgcapWhite
+ - type: loadout
+ id: LoadoutMedicalHeadSurgcapCybersun
+
+- type: characterItemGroup
+ id: LoadoutEyesMedical
+ items:
+ - type: loadout
+ id: LoadoutMedicalEyesHudMedical
+ - type: loadout
+ id: LoadoutMedicalEyesEyepatchHudMedical
+ - type: loadout
+ id: LoadoutMedicalEyesHudMedicalPrescription
+ - type: loadout
+ id: LoadoutMedicalEyesGlassesChemical
+ - type: loadout
+ id: LoadoutMedicalEyesGlassesChemist
+
+- type: characterItemGroup
+ id: LoadoutShoesMedical
+ items:
+ - type: loadout
+ id: LoadoutMedicalShoesEnclosedChem
diff --git a/Resources/Prototypes/CharacterItemGroups/musicianInstrumentsGroups.yml b/Resources/Prototypes/CharacterItemGroups/musicianInstrumentsGroups.yml
new file mode 100644
index 0000000000..ccad399e74
--- /dev/null
+++ b/Resources/Prototypes/CharacterItemGroups/musicianInstrumentsGroups.yml
@@ -0,0 +1,31 @@
+- type: characterItemGroup
+ id: LoadoutMusicianInstruments
+ maxItems: 3
+ items:
+ - type: loadout
+ id: LoadoutItemSynthesizerInstrumentMusician
+ - type: loadout
+ id: LoadoutItemMicrophoneInstrumentMusician
+ - type: loadout
+ id: LoadoutItemKalimbaInstrumentMusician
+ - type: loadout
+ id: LoadoutItemTrumpetInstrumentMusician
+ - type: loadout
+ id: LoadoutItemElectricGuitarInstrumentMusician
+ - type: loadout
+ id: LoadoutItemBassGuitarInstrumentMusician
+ - type: loadout
+ id: LoadoutItemRockGuitarInstrumentMusician
+ - type: loadout
+ id: LoadoutItemAcousticGuitarInstrumentMusician
+ - type: loadout
+ id: LoadoutItemViolinInstrumentMusician
+ - type: loadout
+ id: LoadoutItemHarmonicaInstrumentMusician
+ - type: loadout
+ id: LoadoutItemAccordionInstrumentMusician
+ - type: loadout
+ id: LoadoutItemFluteInstrumentMusician
+ - type: loadout
+ id: LoadoutItemOcarinaInstrumentMusician
+
diff --git a/Resources/Prototypes/CharacterItemGroups/scienceGroups.yml b/Resources/Prototypes/CharacterItemGroups/scienceGroups.yml
new file mode 100644
index 0000000000..e5e43760da
--- /dev/null
+++ b/Resources/Prototypes/CharacterItemGroups/scienceGroups.yml
@@ -0,0 +1,103 @@
+- type: characterItemGroup
+ id: LoadoutUniformsScience
+ items:
+ - type: loadout
+ id: LoadoutScienceUniformJumpskirtSenior
+ - type: loadout
+ id: LoadoutScienceUniformJumpsuitSenior
+ - type: loadout
+ id: LoadoutScienceUniformJumpskirtRoboticist
+ - type: loadout
+ id: LoadoutScienceUniformJumpsuitRoboticist
+ - type: loadout
+ id: LoadoutScienceUniformJumpsuitMonasticRobeDark
+ - type: loadout
+ id: LoadoutScienceUniformJumpsuitMonasticRobeLight
+
+- type: characterItemGroup
+ id: LoadoutOuterScience
+ items:
+ - type: loadout
+ id: LoadoutScienceOuterCoat
+ - type: loadout
+ id: LoadoutScienceOuterLabcoat
+ - type: loadout
+ id: LoadoutSciencegOuterCoatRobo
+ - type: loadout
+ id: LoadoutScienceOuterWinterSci
+ - type: loadout
+ id: LoadoutScienceOuterLabcoatSeniorResearcher
+ - type: loadout
+ id: LoadoutScienceOuterExplorerLabcoat
+ - type: loadout
+ id: LoadoutOuterRobeTechPriest
+ - type: loadout
+ id: LoadoutOuterPlagueSuit
+ - type: loadout
+ id: LoadoutOuterNunRobe
+ - type: loadout
+ id: LoadoutOuterHoodieBlack
+ - type: loadout
+ id: LoadoutOuterHoodieChaplain
+ - type: loadout
+ id: LoadoutScienceOuterWinterCoatMantis
+
+- type: characterItemGroup
+ id: LoadoutGlovesScience
+ items:
+ - type: loadout
+ id: LoadoutScienceHandsGlovesColorPurple
+ - type: loadout
+ id: LoadoutScienceHandsGlovesLatex
+ - type: loadout
+ id: LoadoutScienceHandsGlovesRobohands
+
+- type: characterItemGroup
+ id: LoadoutNeckScience
+ items:
+ - type: loadout
+ id: LoadoutScienceNeckTieSci
+ - type: loadout
+ id: LoadoutScienceNeckScarfStripedPurple
+ - type: loadout
+ id: LoadoutScienceNeckStoleChaplain
+ - type: loadout
+ id: LoadoutScienceNeckScarfStripedBlack
+
+- type: characterItemGroup
+ id: LoadoutMaskScience
+ items:
+ - type: loadout
+ id: LoadoutScienceMaskPlague
+
+- type: characterItemGroup
+ id: LoadoutHeadScience
+ items:
+ - type: loadout
+ id: LoadoutScienceHeadHatBeret
+ - type: loadout
+ id: LoadoutHeadHoodTechPriest
+ - type: loadout
+ id: LoadoutScienceHeadHatFez
+ - type: loadout
+ id: LoadoutScienceHeadHatHoodNunHood
+ - type: loadout
+ id: LoadoutScienceHeadHatPlaguedoctor
+ - type: loadout
+ id: LoadoutScienceHeadHatWitch
+ - type: loadout
+ id: LoadoutScienceHeadHatWitch1
+
+- type: characterItemGroup
+ id: LoadoutEyesScience
+ items:
+ - type: loadout
+ id: LoadoutScienceEyesHudDiagnostic
+ - type: loadout
+ id: LoadoutScienceEyesEyepatchHudDiag
+
+- type: characterItemGroup
+ id: LoadoutShoesScience
+ items:
+ - type: loadout
+ id: LoadoutScienceShoesBootsWinterSci
diff --git a/Resources/Prototypes/CharacterItemGroups/securityGroups.yml b/Resources/Prototypes/CharacterItemGroups/securityGroups.yml
new file mode 100644
index 0000000000..edd5f8700a
--- /dev/null
+++ b/Resources/Prototypes/CharacterItemGroups/securityGroups.yml
@@ -0,0 +1,142 @@
+- type: characterItemGroup
+ id: LoadoutUniformsSecurity
+ items:
+ - type: loadout
+ id: LoadoutSecurityUniformJumpsuitBlue
+ - type: loadout
+ id: LoadoutSecurityUniformJumpskirtBlue
+ - type: loadout
+ id: LoadoutSecurityUniformJumpsuitGrey
+ - type: loadout
+ id: LoadoutSecurityUniformJumpskirtGrey
+ - type: loadout
+ id: LoadoutSecurityUniformJumpsuitSenior
+ - type: loadout
+ id: LoadoutSecurityUniformJumpskirtSenior
+ - type: loadout
+ id: LoadoutSecurityUniformJumpsuitWardenBlue
+ - type: loadout
+ id: LoadoutSecurityUniformJumpskirtWardenBlue
+ - type: loadout
+ id: LoadoutSecurityUniformJumpsuitWardenGrey
+ - type: loadout
+ id: LoadoutSecurityUniformJumpskirtWardenGrey
+ - type: loadout
+ id: LoadoutSecurityUniformJumpsuitHoSBlue
+ - type: loadout
+ id: LoadoutSecurityUniformJumpskirtHoSBlue
+ - type: loadout
+ id: LoadoutSecurityUniformJumpsuitHoSGrey
+ - type: loadout
+ id: LoadoutSecurityUniformJumpskirtHoSGrey
+ - type: loadout
+ id: LoadoutUniformJumpsuitSecFormal
+ - type: loadout
+ id: LoadoutUniformJumpsuitSecSummer
+
+- type: characterItemGroup
+ id: LoadoutOuterSecurity
+ items:
+ - type: loadout
+ id: LoadoutClothingOuterArmorPlateCarrier
+ - type: loadout
+ id: LoadoutClothingOuterArmorDuraVest
+ - type: loadout
+ id: LoadoutClothingOuterCoatDetective
+ - type: loadout
+ id: LoadoutOuterVestDetective
+ - type: loadout
+ id: LoadoutClothingOuterCoatWarden
+ - type: loadout
+ id: LoadoutClothingOuterCoatHoSTrench
+ - type: loadout
+ id: LoadoutClothingOuterWinterHoS
+
+- type: characterItemGroup
+ id: LoadoutGlovesSecurity
+ items:
+ - type: loadout
+ id: LoadoutClothingHandsGlovesNitrile
+
+- type: characterItemGroup
+ id: LoadoutNeckSecurity
+ items:
+ - type: loadout
+ id: LoadoutClothingNeckCloakHos
+ - type: loadout
+ id: LoadoutClothingNeckMantleHOS
+ - type: loadout
+ id: LoadoutBedsheetBrigmedic
+
+- type: characterItemGroup
+ id: LoadoutHeadSecurity
+ items:
+ - type: loadout
+ id: LoadoutSecurityHeadHatBeret
+ - type: loadout
+ id: LoadoutClothingHeadHelmetBasic
+ - type: loadout
+ id: LoadoutClothingHeadHatBeretBrigmedic
+ - type: loadout
+ id: LoadoutClothingHeadHatBeretCorpsman
+ - type: loadout
+ id: LoadoutClothingHeadHatBeretWarden
+ - type: loadout
+ id: LoadoutClothingHeadHatBeretHoS
+ - type: loadout
+ id: LoadoutClothingHeadHelmetInsulated
+
+- type: characterItemGroup
+ id: LoadoutMaskSecurity
+ items:
+ - type: loadout
+ id: LoadoutSecurityMaskGasSwat
+
+- type: characterItemGroup
+ id: LoadoutBeltSecurity
+ items:
+ - type: loadout
+ id: LoadoutSecurityBeltWebbing
+ - type: loadout
+ id: LoadoutClothingBeltCorpsmanWebbing
+ - type: loadout
+ id: LoadoutClothingBeltSecurity
+
+- type: characterItemGroup
+ id: LoadoutEyesSecurity
+ items:
+ - type: loadout
+ id: LoadoutSecurityEyesHudSecurity
+ - type: loadout
+ id: ClothingEyesGlassesSunglasses
+ - type: loadout
+ id: LoadoutSecurityEyesEyepatchHudSecurity
+ - type: loadout
+ id: LoadoutSecurityEyesHudSecurityPrescription
+ - type: loadout
+ id: LoadoutClothingEyesGlassesSecurity
+
+- type: characterItemGroup
+ id: LoadoutShoesSecurity
+ items:
+ - type: loadout
+ id: LoadoutSecurityShoesJackboots
+ - type: loadout
+ id: LoadoutClothingShoesBootsCombat
+
+- type: characterItemGroup
+ maxItems: 5 # No clue what the actual number should be.
+ id: LoadoutEquipmentSecurity
+ items:
+ - type: loadout
+ id: LoadoutSecurityCombatKnife
+ - type: loadout
+ id: LoadoutSecurityFlash
+ - type: loadout
+ id: LoadoutSecurityDisabler
+ - type: loadout
+ id: LoadoutMagazinePistolRubber
+ - type: loadout
+ id: LoadoutSpeedLoaderMagnumRubber
+
+
diff --git a/Resources/Prototypes/CharacterItemGroups/serviceGroups.yml b/Resources/Prototypes/CharacterItemGroups/serviceGroups.yml
new file mode 100644
index 0000000000..01ec0aaeea
--- /dev/null
+++ b/Resources/Prototypes/CharacterItemGroups/serviceGroups.yml
@@ -0,0 +1,100 @@
+- type: characterItemGroup
+ id: LoadoutUniformsService
+ items:
+ - type: loadout
+ id: LoadoutServiceClownOutfitJester
+ - type: loadout
+ id: LoadoutServiceClownOutfitJesterAlt
+ - type: loadout
+ id: LoadoutServiceBartenderUniformPurple
+ - type: loadout
+ id: LoadoutServiceBotanistUniformOveralls
+ - type: loadout
+ id: LoadoutServiceLawyerUniformBlueSuit
+ - type: loadout
+ id: LoadoutServiceLawyerUniformBlueSkirt
+ - type: loadout
+ id: LoadoutServiceLawyerUniformRedSuit
+ - type: loadout
+ id: LoadoutServiceLawyerUniformRedSkirt
+ - type: loadout
+ id: LoadoutServiceLawyerUniformPurpleSuit
+ - type: loadout
+ id: LoadoutServiceLawyerUniformPurpleSkirt
+ - type: loadout
+ id: LoadoutServiceLawyerUniformGoodSuit
+ - type: loadout
+ id: LoadoutServiceLawyerUniformGoodSkirt
+ - type: loadout
+ id: LoadoutServiceReporterUniformJournalist
+ - type: loadout
+ id: LoadoutServiceReporterUniformDetectivesuit
+ - type: loadout
+ id: LoadoutServiceReporterUniformDetectiveskirt
+
+- type: characterItemGroup
+ id: LoadoutOuterService
+ items:
+ - type: loadout
+ id: LoadoutServiceClownOuterWinter
+ - type: loadout
+ id: LoadoutServiceClownOuterClownPriest
+ - type: loadout
+ id: LoadoutServiceMimeOuterWinter
+
+- type: characterItemGroup
+ id: LoadoutNeckService
+ items:
+ - type: loadout
+ id: LoadoutServiceClownBedsheetClown
+ - type: loadout
+ id: LoadoutServiceMimeBedsheetMime
+
+- type: characterItemGroup
+ id: LoadoutMaskService
+ items:
+ - type: loadout
+ id: LoadoutServiceClownMaskSexy
+ - type: loadout
+ id: LoadoutServiceMimeMaskSad
+ - type: loadout
+ id: LoadoutServiceMimeMaskScared
+ - type: loadout
+ id: LoadoutServiceMimeMaskSexy
+
+- type: characterItemGroup
+ id: LoadoutShoesService
+ items:
+ - type: loadout
+ id: LoadoutServiceClownBootsWinter
+ - type: loadout
+ id: LoadoutServiceMimeShoesBootsWinter
+
+- type: characterItemGroup
+ id: LoadoutEquipmentService
+ items:
+ - type: loadout
+ id: LoadoutServiceClownCowToolboxFilled
+
+# Bartender
+- type: characterItemGroup
+ id: LoadoutBartenderOuterwear
+ items:
+ - type: loadout
+ id: LoadoutServiceBartenderArmorDuraVest
+
+- type: characterItemGroup
+ id: LoadoutBartenderAmmo
+ items:
+ - type: loadout
+ id: LoadoutServiceBartenderBoxBeanbags
+ - type: loadout
+ id: LoadoutServiceBartenderBoxLightRifleRubber
+
+- type: characterItemGroup
+ id: LoadoutBartenderWeapon
+ items:
+ - type: loadout
+ id: LoadoutServiceBartenderShotgunDoubleBarreledRubber
+ - type: loadout
+ id: LoadoutServiceBartenderMosinRubber
diff --git a/Resources/Prototypes/DeltaV/Reagents/Consumable/Drink/drinks.yml b/Resources/Prototypes/DeltaV/Reagents/Consumable/Drink/drinks.yml
index c568c1bc75..7fdc51f1de 100644
--- a/Resources/Prototypes/DeltaV/Reagents/Consumable/Drink/drinks.yml
+++ b/Resources/Prototypes/DeltaV/Reagents/Consumable/Drink/drinks.yml
@@ -19,7 +19,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.3
+ amount: 0.336
- !type:PopupMessage
conditions:
- !type:ReagentThreshold
@@ -55,7 +55,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.20
+ amount: 0.133
Poison:
effects:
- !type:HealthChange
@@ -83,7 +83,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.15
+ amount: 0.16
- type: reagent
id: GreenGrass
@@ -105,7 +105,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.05
+ amount: 0.083
- type: reagent
id: Daiquiri
@@ -128,7 +128,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.25
+ amount: 0.3
- type: reagent
id: ArsonistsBrew
@@ -151,7 +151,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.30
+ amount: 0.08
Poison:
effects:
- !type:HealthChange
@@ -179,6 +179,14 @@
metamorphicMaxFillLevels: 4
metamorphicFillBaseName: fill-
metamorphicChangeColor: false
+ metabolisms:
+ Drink:
+ effects:
+ - !type:SatiateThirst
+ factor: 2
+ - !type:AdjustReagent
+ reagent: Ethanol
+ amount: 0.015
- type: reagent
id: Mothamphetamine
@@ -201,7 +209,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.25
+ amount: 0.126
Poison:
effects:
- !type:Jitter
diff --git a/Resources/Prototypes/Entities/Clothing/Shoes/magboots.yml b/Resources/Prototypes/Entities/Clothing/Shoes/magboots.yml
index 880239b51e..9381b3f208 100644
--- a/Resources/Prototypes/Entities/Clothing/Shoes/magboots.yml
+++ b/Resources/Prototypes/Entities/Clothing/Shoes/magboots.yml
@@ -28,6 +28,10 @@
- type: Tag
tags:
- WhitelistChameleon
+ - type: ReverseEngineering
+ difficulty: 2
+ recipes:
+ - ClothingShoesBootsMag
- type: entity
parent: ClothingShoesBootsMag
diff --git a/Resources/Prototypes/Entities/Markers/environmental.yml b/Resources/Prototypes/Entities/Markers/environmental.yml
new file mode 100644
index 0000000000..0642518356
--- /dev/null
+++ b/Resources/Prototypes/Entities/Markers/environmental.yml
@@ -0,0 +1,100 @@
+# Radiation
+- type: entity
+ name: Marker Radiation
+ id: MarkerRadiation1
+ parent: MarkerBase
+ suffix: intensity 1
+ components:
+ - type: Sprite
+ layers:
+ - sprite: Markers/environment.rsi
+ state: base-green
+ shader: unshaded
+ - sprite: Markers/environment.rsi
+ shader: unshaded
+ state: rad
+ - type: RadiationSource
+ intensity: 1
+
+- type: entity
+ parent: MarkerRadiation1
+ id: MarkerRadiation2
+ suffix: intensity 2
+ components:
+ - type: RadiationSource
+ intensity: 2
+
+- type: entity
+ parent: MarkerRadiation1
+ id: MarkerRadiation3
+ suffix: intensity 3
+ components:
+ - type: RadiationSource
+ intensity: 3
+
+- type: entity
+ parent: MarkerRadiation1
+ id: MarkerRadiation4
+ suffix: intensity 4
+ components:
+ - type: RadiationSource
+ intensity: 4
+
+- type: entity
+ parent: MarkerRadiation1
+ id: MarkerRadiation5
+ suffix: intensity 5
+ components:
+ - type: RadiationSource
+ intensity: 5
+
+- type: entity
+ parent: MarkerRadiation1
+ id: MarkerRadiation10
+ suffix: intensity 10
+ components:
+ - type: RadiationSource
+ intensity: 10
+
+# Invisible Walls
+- type: entity
+ name: Marker Blocker
+ id: MarkerBlocker
+ parent: MarkerBase
+ suffix: invisible wall
+ components:
+ - type: Sprite
+ layers:
+ - sprite: Markers/environment.rsi
+ state: base-blue
+ shader: unshaded
+ - sprite: Markers/environment.rsi
+ shader: unshaded
+ state: wall
+ - type: PlacementReplacement
+ key: blocker
+ - type: Fixtures
+ fixtures:
+ fix1:
+ shape:
+ !type:PhysShapeAabb
+ bounds: "-0.5,-0.5,0.5,0.5"
+ mask:
+ - FullTileMask
+ layer:
+ - WallLayer
+ density: 1000
+ - type: Physics
+ bodyType: Static
+
+
+# Weather Blocker
+- type: entity
+ name: Marker Weather Blocker
+ id: MarkerWeatherblocker
+ parent: MarkerBase
+ components:
+ - type: Sprite
+ sprite: Markers/environment.rsi
+ state: weather
+ - type: BlockWeather
diff --git a/Resources/Prototypes/Entities/Mobs/Species/harpy.yml b/Resources/Prototypes/Entities/Mobs/Species/harpy.yml
index 788b21eafb..05ac3de8bb 100644
--- a/Resources/Prototypes/Entities/Mobs/Species/harpy.yml
+++ b/Resources/Prototypes/Entities/Mobs/Species/harpy.yml
@@ -5,6 +5,10 @@
id: MobHarpyBase
abstract: true
components:
+ - type: Flight
+ isLayerAnimated: true
+ layer: "/Textures/Mobs/Customization/Harpy/harpy_wings.rsi"
+ animationKey: "Flap"
- type: Singer
proto: HarpySinger
- type: Sprite
@@ -197,3 +201,15 @@
icon: DeltaV/Interface/Actions/harpy_syrinx.png
itemIconStyle: BigAction
event: !type:VoiceMaskSetNameEvent
+
+- type: entity
+ id: ActionToggleFlight
+ name: Fly
+ description: Make use of your wings to fly. Beat the flightless bird allegations.
+ noSpawn: true
+ components:
+ - type: InstantAction
+ checkCanInteract: false
+ icon: { sprite: Interface/Actions/flight.rsi, state: flight_off }
+ iconOn: { sprite : Interface/Actions/flight.rsi, state: flight_on }
+ event: !type:ToggleFlightEvent
\ No newline at end of file
diff --git a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml
index 62f3bbcb3f..891dfc1e79 100644
--- a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml
+++ b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml
@@ -29,6 +29,10 @@
Amount: 1
DefaultPrototype: Igniter
ExamineName: Igniter
+ - type: ReverseEngineering # Delta
+ difficulty: 2
+ recipes:
+ - AutolatheHyperConvectionMachineCircuitboard
- type: entity
id: ProtolatheMachineCircuitboard
@@ -66,6 +70,10 @@
Amount: 1
DefaultPrototype: Igniter
ExamineName: Igniter
+ - type: ReverseEngineering # Delta
+ difficulty: 2
+ recipes:
+ - ProtolatheHyperConvectionMachineCircuitboard
- type: entity
id: BiofabricatorMachineCircuitboard
@@ -79,6 +87,10 @@
MatterBin: 4
materialRequirements:
Glass: 1
+ - type: ReverseEngineering # Delta
+ difficulty: 2
+ recipes:
+ - BiofabricatorMachineCircuitboard
- type: entity
id: SecurityTechFabCircuitboard
@@ -151,10 +163,6 @@
Amount: 2
DefaultPrototype: Beaker
ExamineName: Glass Beaker
- - type: ReverseEngineering # Nyano
- difficulty: 3
- recipes:
- - CircuitImprinterMachineCircuitboard
- type: entity
id: ExosuitFabricatorMachineCircuitboard
@@ -171,7 +179,7 @@
materialRequirements:
Glass: 5
- type: ReverseEngineering # Nyano
- difficulty: 3
+ difficulty: 2
recipes:
- ExosuitFabricatorMachineCircuitboard
- type: GuideHelp
@@ -202,10 +210,6 @@
requirements:
MatterBin: 1
Manipulator: 2
- - type: ReverseEngineering # Nyano
- difficulty: 2
- recipes:
- - UniformPrinterMachineCircuitboard
- type: entity
id: VaccinatorMachineCircuitboard
@@ -313,6 +317,10 @@
materialRequirements:
Glass: 1
Steel: 5
+ - type: ReverseEngineering # Delta
+ difficulty: 3
+ recipes:
+ - ArtifactCrusherMachineCircuitboard
- type: entity
parent: BaseMachineCircuitboard
@@ -350,6 +358,10 @@
Cable: 5
PlasmaGlass: 15
MetalRod: 4
+ - type: ReverseEngineering # Nyano
+ difficulty: 2
+ recipes:
+ - AnomalyVesselExperimentalCircuitboard
- type: entity
parent: BaseMachineCircuitboard
@@ -367,6 +379,10 @@
materialRequirements:
PlasmaGlass: 5
Cable: 5
+ - type: ReverseEngineering # Delta
+ difficulty: 3
+ recipes:
+ - AnomalySynchronizerCircuitboard
- type: entity
parent: BaseMachineCircuitboard
@@ -451,6 +467,10 @@
deconstructionTarget: null
graph: ThermomachineBoard
node: hellfirefreezer
+ - type: ReverseEngineering # Delta
+ difficulty: 3
+ recipes:
+ - HellfireFreezerMachineCircuitBoard
- type: entity
parent: BaseMachineCircuitboard
@@ -596,6 +616,10 @@
materialRequirements:
Steel: 1
Cable: 2
+ - type: ReverseEngineering # Delta
+ difficulty: 3
+ recipes:
+ - CrewMonitoringServerMachineCircuitboard
- type: entity
id: CryoPodMachineCircuitboard
@@ -635,10 +659,6 @@
Amount: 2
DefaultPrototype: Beaker
ExamineName: Glass Beaker
- - type: ReverseEngineering # Nyano
- difficulty: 2
- recipes:
- - ChemMasterMachineCircuitboard
- type: entity
id: ChemDispenserMachineCircuitboard
@@ -660,10 +680,6 @@
Amount: 2
DefaultPrototype: Beaker
ExamineName: Glass Beaker
- - type: ReverseEngineering # Nyano
- difficulty: 2
- recipes:
- - ChemDispenserMachineCircuitboard
- type: entity
id: BiomassReclaimerMachineCircuitboard
@@ -750,9 +766,6 @@
PowerCell: 4
materialRequirements:
CableHV: 10
- - type: ReverseEngineering # Nyano
- recipes:
- - SMESMachineCircuitboard
- type: entity
id: CellRechargerCircuitboard
@@ -862,6 +875,10 @@
materialComposition:
Steel: 30
Plastic: 30
+ - type: ReverseEngineering # Delta
+ difficulty: 2
+ recipes:
+ - TurboItemRechargerCircuitboard
- type: entity
id: SubstationMachineCircuitboard
@@ -877,9 +894,6 @@
materialRequirements:
CableMV: 5
CableHV: 5
- - type: ReverseEngineering # Nyano
- recipes:
- - SubstationMachineCircuitboard
- type: PhysicalComposition
materialComposition:
Glass: 200
@@ -921,7 +935,7 @@
DefaultPrototype: SaxophoneInstrument
ExamineName: Woodwind Instrument
- type: ReverseEngineering # Nyano
- difficulty: 3
+ difficulty: 2
recipes:
- DawInstrumentMachineCircuitboard
@@ -938,10 +952,6 @@
Capacitor: 1
materialRequirements:
CableHV: 5
- - type: ReverseEngineering # Nyano
- difficulty: 2
- recipes:
- - GeneratorPlasmaMachineCircuitboard
- type: PhysicalComposition
materialComposition:
Glass: 200
@@ -949,6 +959,10 @@
Silicon: 20
- type: StaticPrice
price: 40
+ - type: ReverseEngineering # Nyano
+ difficulty: 2
+ recipes:
+ - PortableGeneratorPacmanMachineCircuitboard
- type: entity
id: ThrusterMachineCircuitboard
@@ -961,6 +975,10 @@
Capacitor: 4
materialRequirements:
Steel: 5
+ - type: ReverseEngineering # Delta
+ difficulty: 3
+ recipes:
+ - ThrusterMachineCircuitboard
- type: entity
id: GyroscopeMachineCircuitboard
@@ -974,6 +992,10 @@
Capacitor: 1
materialRequirements:
Glass: 2
+ - type: ReverseEngineering # Delta
+ difficulty: 3
+ recipes:
+ - GyroscopeMachineCircuitboard
- type: entity
id: PortableGeneratorSuperPacmanMachineCircuitboard
@@ -993,12 +1015,12 @@
Glass: 200
chemicalComposition:
Silicon: 20
+ - type: StaticPrice
+ price: 40
- type: ReverseEngineering # Nyano
difficulty: 2
recipes:
- PortableGeneratorSuperPacmanMachineCircuitboard
- - type: StaticPrice
- price: 40
- type: entity
id: PortableGeneratorJrPacmanMachineCircuitboard
@@ -1020,6 +1042,10 @@
Silicon: 20
- type: StaticPrice
price: 40
+ - type: ReverseEngineering # Nyano
+ difficulty: 2
+ recipes:
+ - PortableGeneratorJrPacmanMachineCircuitboard
- type: entity
id: ReagentGrinderMachineCircuitboard
@@ -1054,7 +1080,7 @@
Capacitor: 2
materialRequirements:
Glass: 1
- - type: ReverseEngineering # Nyano
+ - type: ReverseEngineering # Delta
difficulty: 2
recipes:
- HotplateMachineCircuitboard
@@ -1072,6 +1098,10 @@
materialRequirements:
Glass: 2
Cable: 5
+ - type: ReverseEngineering # Delta
+ difficulty: 2
+ recipes:
+ - ElectricGrillMachineCircuitboard
- type: entity
id: StasisBedMachineCircuitboard
@@ -1137,6 +1167,10 @@
materialRequirements:
Steel: 5
Plastic: 5
+ - type: ReverseEngineering # Delta
+ difficulty: 2
+ recipes:
+ - MaterialReclaimerMachineCircuitboard
- type: entity
id: OreProcessorMachineCircuitboard
@@ -1152,9 +1186,6 @@
Manipulator: 3
materialRequirements:
Glass: 1
- - type: ReverseEngineering # Nyano
- recipes:
- - OreProcessorMachineCircuitboard
- type: entity
parent: BaseMachineCircuitboard
@@ -1170,6 +1201,10 @@
Manipulator: 3
materialRequirements:
Glass: 1
+ - type: ReverseEngineering # Delta
+ difficulty: 2
+ recipes:
+ - OreProcessorIndustrialMachineCircuitboard
- type: entity
id: SheetifierMachineCircuitboard
@@ -1216,6 +1251,10 @@
Amount: 1
DefaultPrototype: ForkPlastic
ExamineName: Utensil
+ - type: ReverseEngineering # Delta
+ difficulty: 2
+ recipes:
+ - FatExtractorMachineCircuitboard
- type: entity
parent: BaseMachineCircuitboard
@@ -1229,6 +1268,10 @@
MatterBin: 1
materialRequirements:
Steel: 1
+ - type: ReverseEngineering # Delta
+ difficulty: 2
+ recipes:
+ - FlatpackerMachineCircuitboard
- type: entity
id: EmitterCircuitboard
@@ -1348,9 +1391,6 @@
Amount: 1
DefaultPrototype: Beaker
ExamineName: Glass Beaker
- - type: ReverseEngineering # Nyano
- recipes:
- - BoozeDispenserMachineCircuitboard
- type: entity
id: CargoTelepadMachineCircuitboard
@@ -1367,6 +1407,10 @@
materialRequirements:
Steel: 5
Bluespace: 2 #DeltaV Bluespace Exists
+ - type: ReverseEngineering # Delta
+ difficulty: 3
+ recipes:
+ - CargoTelepadMachineCircuitboard
- type: entity
id: SodaDispenserMachineCircuitboard
@@ -1385,9 +1429,6 @@
Amount: 1
DefaultPrototype: Beaker
ExamineName: Glass Beaker
- - type: ReverseEngineering # Nyano
- recipes:
- - SodaDispenserMachineCircuitboard
- type: entity
id: TelecomServerCircuitboard
@@ -1437,6 +1478,10 @@
Steel: 5
CableHV: 5
Uranium: 2
+ - type: ReverseEngineering # Delta
+ difficulty: 3
+ recipes:
+ - MiniGravityGeneratorCircuitboard
- type: entity
id: ShuttleGunSvalinnMachineGunCircuitboard
@@ -1454,6 +1499,10 @@
materialRequirements:
Steel: 5
CableHV: 5
+ - type: ReverseEngineering # Delta
+ difficulty: 3
+ recipes:
+ - ShuttleGunSvalinnMachineGunCircuitboard
- type: entity
id: ShuttleGunPerforatorCircuitboard
@@ -1471,6 +1520,10 @@
materialRequirements:
Steel: 10
CableHV: 5
+ - type: ReverseEngineering # Delta
+ difficulty: 3
+ recipes:
+ - ShuttleGunPerforatorCircuitboard
- type: entity
id: ShuttleGunFriendshipCircuitboard
@@ -1488,6 +1541,10 @@
materialRequirements:
Steel: 7
CableHV: 5
+ - type: ReverseEngineering # Delta
+ difficulty: 3
+ recipes:
+ - ShuttleGunFriendshipCircuitboard
- type: entity
id: ShuttleGunDusterCircuitboard
@@ -1506,6 +1563,10 @@
Steel: 10
CableHV: 5
Uranium: 2
+ - type: ReverseEngineering # Delta
+ difficulty: 4
+ recipes:
+ - ShuttleGunDusterCircuitboard
- type: entity
id: ShuttleGunKineticCircuitboard
@@ -1523,6 +1584,10 @@
materialRequirements:
Steel: 5
CableHV: 2
+ - type: ReverseEngineering # Delta
+ difficulty: 2
+ recipes:
+ - ShuttleGunKineticCircuitboard
- type: entity
parent: BaseMachineCircuitboard
@@ -1536,6 +1601,10 @@
Manipulator: 3
materialRequirements:
Glass: 1
+ - type: ReverseEngineering # Delta
+ difficulty: 2
+ recipes:
+ - ReagentGrinderIndustrialMachineCircuitboard
- type: entity
parent: BaseMachineCircuitboard
@@ -1550,3 +1619,8 @@
Steel: 2
Glass: 5
Cable: 2
+ - type: ReverseEngineering # Delta
+ difficulty: 2
+ recipes:
+ - JukeboxCircuitBoard
+
diff --git a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/computer.yml b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/computer.yml
index 833ca2becd..35a941e759 100644
--- a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/computer.yml
+++ b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/computer.yml
@@ -122,6 +122,10 @@
prototype: ComputerSalvageExpedition
- type: StealTarget
stealGroup: SalvageExpeditionsComputerCircuitboard
+ - type: ReverseEngineering # Nyano
+ difficulty: 2
+ recipes:
+ - SalvageExpeditionsComputerCircuitboard
- type: entity
parent: BaseComputerCircuitboard
@@ -177,6 +181,10 @@
- type: Tag
tags:
- ComputerTelevisionCircuitboard
+ - type: ReverseEngineering # Nyano
+ difficulty: 2
+ recipes:
+ - ComputerTelevisionCircuitboard
- type: entity
parent: BaseComputerCircuitboard
@@ -286,6 +294,10 @@
components:
- type: ComputerBoard
prototype: ComputerRadar
+ - type: ReverseEngineering # Nyano
+ difficulty: 2
+ recipes:
+ - RadarConsoleCircuitboard
- type: entity
parent: BaseComputerCircuitboard
@@ -339,6 +351,10 @@
components:
- type: ComputerBoard
prototype: ComputerShuttle
+ - type: ReverseEngineering # Nyano
+ difficulty: 3
+ recipes:
+ - ShuttleConsoleCircuitboard
- type: entity
parent: BaseComputerCircuitboard
@@ -396,6 +412,10 @@
price: 150
- type: ComputerBoard
prototype: ComputerMassMedia
+ - type: ReverseEngineering # Nyano
+ difficulty: 3
+ recipes:
+ - ComputerMassMediaCircuitboard
- type: entity
parent: BaseComputerCircuitboard
diff --git a/Resources/Prototypes/Entities/Objects/Devices/hand_teleporter.yml b/Resources/Prototypes/Entities/Objects/Devices/hand_teleporter.yml
index 2e6c2d8c27..deac20e05e 100644
--- a/Resources/Prototypes/Entities/Objects/Devices/hand_teleporter.yml
+++ b/Resources/Prototypes/Entities/Objects/Devices/hand_teleporter.yml
@@ -9,10 +9,6 @@
layers:
- state: icon
- type: HandTeleporter
- - type: ReverseEngineering # Nyano
- difficulty: 4
- recipes:
- - HandTeleporter
- type: Tag
tags:
- HighRiskItem
diff --git a/Resources/Prototypes/Entities/Objects/Devices/holoprojectors.yml b/Resources/Prototypes/Entities/Objects/Devices/holoprojectors.yml
index 5cbf64c560..b7ad8ddd6a 100644
--- a/Resources/Prototypes/Entities/Objects/Devices/holoprojectors.yml
+++ b/Resources/Prototypes/Entities/Objects/Devices/holoprojectors.yml
@@ -68,6 +68,7 @@
- type: StaticPrice
price: 80
- type: ReverseEngineering # Nyano
+ difficulty: 3
recipes:
- HolofanProjector
@@ -98,6 +99,10 @@
- HolofanProjector
- type: StaticPrice
price: 130
+ - type: ReverseEngineering # Nyano
+ difficulty: 3
+ recipes:
+ - HoloprojectorField
- type: entity
parent: HoloprojectorField
diff --git a/Resources/Prototypes/Entities/Objects/Devices/swapper.yml b/Resources/Prototypes/Entities/Objects/Devices/swapper.yml
index 8a743f4796..3ab014b28c 100644
--- a/Resources/Prototypes/Entities/Objects/Devices/swapper.yml
+++ b/Resources/Prototypes/Entities/Objects/Devices/swapper.yml
@@ -25,3 +25,7 @@
- type: Tag
tags:
- QuantumSpinInverter
+ - type: ReverseEngineering # Delta
+ difficulty: 4
+ recipes:
+ - DeviceQuantumSpinInverter
diff --git a/Resources/Prototypes/Entities/Objects/Specific/chemistry.yml b/Resources/Prototypes/Entities/Objects/Specific/chemistry.yml
index 9e68879fb4..fd32523d8f 100644
--- a/Resources/Prototypes/Entities/Objects/Specific/chemistry.yml
+++ b/Resources/Prototypes/Entities/Objects/Specific/chemistry.yml
@@ -227,6 +227,10 @@
beaker:
maxVol: 60
canReact: false
+ - type: ReverseEngineering # Delta
+ difficulty: 3
+ recipes:
+ - CryostasisBeaker
- type: entity
name: bluespace beaker
@@ -245,6 +249,10 @@
beaker:
maxVol: 1000
canMix: true
+ - type: ReverseEngineering # Delta
+ difficulty: 4
+ recipes:
+ - BluespaceBeaker
- type: entity
name: dropper
@@ -401,6 +409,10 @@
tags:
- Syringe
- Trash
+ - type: ReverseEngineering # Delta
+ difficulty: 4
+ recipes:
+ - SyringeBluespace
- type: entity
id: SyringeCryostasis
@@ -432,7 +444,10 @@
tags:
- Syringe
- Trash
-
+ - type: ReverseEngineering # Delta
+ difficulty: 3
+ recipes:
+ - SyringeCryostasis
- type: entity
name: pill
diff --git a/Resources/Prototypes/Entities/Objects/Tools/handheld_mass_scanner.yml b/Resources/Prototypes/Entities/Objects/Tools/handheld_mass_scanner.yml
index 5647737219..131bb1960b 100644
--- a/Resources/Prototypes/Entities/Objects/Tools/handheld_mass_scanner.yml
+++ b/Resources/Prototypes/Entities/Objects/Tools/handheld_mass_scanner.yml
@@ -38,6 +38,10 @@
type: RadarConsoleBoundUserInterface
- type: StaticPrice
price: 150
+ - type: ReverseEngineering # Delta
+ difficulty: 3
+ recipes:
+ - HandHeldMassScanner
- type: entity
id: HandHeldMassScannerEmpty
@@ -69,4 +73,4 @@
name: power-cell-slot-component-slot-name-default
startingItem: PowerCellMicroreactor
disableEject: true
- swap: false
\ No newline at end of file
+ swap: false
diff --git a/Resources/Prototypes/Entities/Objects/Tools/jaws_of_life.yml b/Resources/Prototypes/Entities/Objects/Tools/jaws_of_life.yml
index 36d2f1308f..12521ff644 100644
--- a/Resources/Prototypes/Entities/Objects/Tools/jaws_of_life.yml
+++ b/Resources/Prototypes/Entities/Objects/Tools/jaws_of_life.yml
@@ -58,6 +58,10 @@
angle: 20
soundHit:
collection: MetalThud
+ - type: ReverseEngineering # Delta
+ difficulty: 3
+ recipes:
+ - JawsOfLife
- type: entity
name: syndicate jaws of life
diff --git a/Resources/Prototypes/Entities/Objects/Tools/tools.yml b/Resources/Prototypes/Entities/Objects/Tools/tools.yml
index a6926f1d8c..c0d4fa179f 100644
--- a/Resources/Prototypes/Entities/Objects/Tools/tools.yml
+++ b/Resources/Prototypes/Entities/Objects/Tools/tools.yml
@@ -413,10 +413,6 @@
Plastic: 100
# - type: DynamicPrice
# price: 100
- - type: ReverseEngineering # Nyano
- difficulty: 2
- recipes:
- - PowerDrill
- type: StaticPrice
price: 100
- type: MeleeWeapon
@@ -433,6 +429,10 @@
angle: 20
soundHit:
path: "/Audio/Items/drill_hit.ogg"
+ - type: ReverseEngineering # Nyano
+ difficulty: 2
+ recipes:
+ - PowerDrill
- type: entity
id: RCD
@@ -478,7 +478,7 @@
- type: PhysicalComposition
materialComposition:
Steel: 600
- Plastic: 100
+ Plastic: 150
- type: StaticPrice
price: 100
- type: UserInterface
@@ -487,6 +487,10 @@
type: RCDMenuBoundUserInterface
- type: ActivatableUI
key: enum.RcdUiKey.Key
+ - type: ReverseEngineering # Nyano
+ difficulty: 3
+ recipes:
+ - RCD
- type: entity
id: RCDEmpty
@@ -548,7 +552,7 @@
heldPrefix: ammo
- type: PhysicalComposition
materialComposition:
- Steel: 100
+ Steel: 300
Plastic: 100
- type: StaticPrice
price: 60
diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Snipers/snipers.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Snipers/snipers.yml
index adb8e323f4..4b58642c30 100644
--- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Snipers/snipers.yml
+++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Snipers/snipers.yml
@@ -55,6 +55,16 @@
path: /Audio/Weapons/Guns/Gunshots/sniper.ogg
fireOnDropChance: 1
+- type: entity
+ name: Kardashev-Mosin
+ parent: WeaponSniperMosin
+ id: WeaponSniperMosinRubber
+ description: A weapon for hunting, or endless trench warfare. Uses .30 rifle rubber ammo.
+ suffix: Non-Lethal
+ components:
+ - type: BallisticAmmoProvider
+ proto: CartridgeLightRifleRubber
+
- type: entity
name: Hristov
parent: BaseWeaponSniper
diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
index c6fa4c38cd..2d4bc9e0d8 100644
--- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
+++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
@@ -355,6 +355,8 @@
- AnimalTranslator
- MofficTranslatorImplanter
- MofficTranslator
+ - RCDAmmo #DeltaV
+ - RCD #EE
- type: EmagLatheRecipes
emagDynamicRecipes:
- ExplosivePayload
@@ -1414,4 +1416,4 @@
- type: MaterialStorage
whitelist:
tags:
- - PrizeTicket
\ No newline at end of file
+ - PrizeTicket
diff --git a/Resources/Prototypes/Guidebook/shiftandcrew.yml b/Resources/Prototypes/Guidebook/shiftandcrew.yml
index 3c4618902e..66f9e7316d 100644
--- a/Resources/Prototypes/Guidebook/shiftandcrew.yml
+++ b/Resources/Prototypes/Guidebook/shiftandcrew.yml
@@ -41,3 +41,4 @@
id: Food Recipes
name: guide-entry-foodrecipes
text: "/ServerInfo/Guidebook/Service/FoodRecipes.xml"
+ filterEnabled: true
diff --git a/Resources/Prototypes/Loadouts/Categories/categories.yml b/Resources/Prototypes/Loadouts/Categories/categories.yml
index 77b1adbe56..80ed6d0efc 100644
--- a/Resources/Prototypes/Loadouts/Categories/categories.yml
+++ b/Resources/Prototypes/Loadouts/Categories/categories.yml
@@ -1,6 +1,6 @@
# Alphabetically ordered, except for Uncategorized since it is always first
# AUncategorized is always first in subcategories to stay consistent with the root Uncategorized
-# AUncategorized is not a spelling mistake, and might have more As added as needed
+# AUncategorized is not a spelling mistake, and might have more As added as needed
- type: loadoutCategory
id: Uncategorized
@@ -27,7 +27,13 @@
root: true
subCategories:
- JobsAUncategorized
+ - JobsCargo
- JobsCommand
+ - JobsEngineering
+ - JobsMedical
+ - JobsScience
+ - JobsSecurity
+ - JobsService
- type: loadoutCategory
id: JobsAUncategorized
@@ -44,7 +50,6 @@
- JobsCommandQM
- JobsCommandRD
-
- type: loadoutCategory
id: JobsCommandAUncategorized
@@ -69,6 +74,32 @@
- type: loadoutCategory
id: JobsCommandRD
+- type: loadoutCategory
+ id: JobsCargo
+
+- type: loadoutCategory
+ id: JobsEngineering
+
+- type: loadoutCategory
+ id: JobsMedical
+
+- type: loadoutCategory
+ id: JobsScience
+
+- type: loadoutCategory
+ id: JobsSecurity
+
+- type: loadoutCategory
+ id: JobsService
+ subCategories:
+ - JobsServiceUncategorized
+ - JobsServiceBartender
+
+- type: loadoutCategory
+ id: JobsServiceUncategorized
+
+- type: loadoutCategory
+ id: JobsServiceBartender
- type: loadoutCategory
id: Mask
diff --git a/Resources/Prototypes/Loadouts/Jobs/Heads/captain.yml b/Resources/Prototypes/Loadouts/Jobs/Heads/captain.yml
index b59f044144..8b4d785476 100644
--- a/Resources/Prototypes/Loadouts/Jobs/Heads/captain.yml
+++ b/Resources/Prototypes/Loadouts/Jobs/Heads/captain.yml
@@ -1,7 +1,7 @@
- type: loadout
id: LoadoutCommandCapNeckMantle
category: JobsCommandCaptain
- cost: 2
+ cost: 0
exclusive: true
requirements:
- !type:CharacterJobRequirement
@@ -13,7 +13,7 @@
- type: loadout
id: LoadoutCommandCapNeckCloak
category: JobsCommandCaptain
- cost: 2
+ cost: 0
exclusive: true
requirements:
- !type:CharacterJobRequirement
@@ -25,7 +25,7 @@
- type: loadout
id: LoadoutCommandCapNeckCloakFormal
category: JobsCommandCaptain
- cost: 2
+ cost: 0
exclusive: true
requirements:
- !type:CharacterJobRequirement
@@ -37,7 +37,7 @@
- type: loadout
id: LoadoutCommandCapJumpsuitFormal
category: JobsCommandCaptain
- cost: 3
+ cost: 0
exclusive: true
requirements:
- !type:CharacterJobRequirement
@@ -49,7 +49,7 @@
- type: loadout
id: LoadoutCommandCapJumpskirtFormal
category: JobsCommandCaptain
- cost: 3
+ cost: 0
exclusive: true
requirements:
- !type:CharacterJobRequirement
@@ -61,7 +61,7 @@
- type: loadout
id: LoadoutCommandCapOuterWinter
category: JobsCommandCaptain
- cost: 2
+ cost: 1
requirements:
- !type:CharacterJobRequirement
jobs:
@@ -72,7 +72,7 @@
- type: loadout
id: LoadoutCommandCapGloves
category: JobsCommandCaptain
- cost: 1
+ cost: 0
requirements:
- !type:CharacterJobRequirement
jobs:
@@ -83,7 +83,7 @@
- type: loadout
id: LoadoutCommandCapHat
category: JobsCommandCaptain
- cost: 1
+ cost: 0
requirements:
- !type:CharacterJobRequirement
jobs:
@@ -94,7 +94,7 @@
- type: loadout
id: LoadoutCommandCapHatCapcap
category: JobsCommandCaptain
- cost: 1
+ cost: 0
requirements:
- !type:CharacterJobRequirement
jobs:
@@ -105,7 +105,7 @@
- type: loadout
id: LoadoutCommandCapHatBeret
category: JobsCommandCaptain
- cost: 1
+ cost: 0
requirements:
- !type:CharacterJobRequirement
jobs:
@@ -116,7 +116,7 @@
- type: loadout
id: LoadoutCommandCapMaskGas
category: JobsCommandCaptain
- cost: 1
+ cost: 0
requirements:
- !type:CharacterJobRequirement
jobs:
@@ -127,7 +127,7 @@
- type: loadout
id: LoadoutCommandCapShoesBootsWinter
category: JobsCommandCaptain
- cost: 1
+ cost: 0
exclusive: true
requirements:
- !type:CharacterJobRequirement
diff --git a/Resources/Prototypes/Loadouts/Jobs/Heads/chiefEngineer.yml b/Resources/Prototypes/Loadouts/Jobs/Heads/chiefEngineer.yml
index 187c06119e..4ac34495ba 100644
--- a/Resources/Prototypes/Loadouts/Jobs/Heads/chiefEngineer.yml
+++ b/Resources/Prototypes/Loadouts/Jobs/Heads/chiefEngineer.yml
@@ -1,7 +1,7 @@
- type: loadout
id: LoadoutCommandCENeckMantle
category: JobsCommandCE
- cost: 2
+ cost: 0
exclusive: true
requirements:
- !type:CharacterJobRequirement
@@ -13,7 +13,7 @@
- type: loadout
id: LoadoutCommandCENeckCloak
category: JobsCommandCE
- cost: 2
+ cost: 0
exclusive: true
requirements:
- !type:CharacterJobRequirement
@@ -25,7 +25,7 @@
- type: loadout
id: LoadoutCommandCEOuterWinter
category: JobsCommandCE
- cost: 2
+ cost: 1
requirements:
- !type:CharacterJobRequirement
jobs:
@@ -36,7 +36,7 @@
- type: loadout
id: LoadoutCommandCEShoesBootsWinter
category: JobsCommandCE
- cost: 1
+ cost: 0
exclusive: true
requirements:
- !type:CharacterJobRequirement
diff --git a/Resources/Prototypes/Loadouts/Jobs/Heads/chiefMedicalOfficer.yml b/Resources/Prototypes/Loadouts/Jobs/Heads/chiefMedicalOfficer.yml
index 8b236a48f4..79d821a8db 100644
--- a/Resources/Prototypes/Loadouts/Jobs/Heads/chiefMedicalOfficer.yml
+++ b/Resources/Prototypes/Loadouts/Jobs/Heads/chiefMedicalOfficer.yml
@@ -1,7 +1,7 @@
- type: loadout
id: LoadoutCommandCMONeckMantle
category: JobsCommandCMO
- cost: 2
+ cost: 0
exclusive: true
requirements:
- !type:CharacterJobRequirement
@@ -13,7 +13,7 @@
- type: loadout
id: LoadoutCommandCMONeckCloak
category: JobsCommandCMO
- cost: 2
+ cost: 0
exclusive: true
requirements:
- !type:CharacterJobRequirement
@@ -25,7 +25,7 @@
- type: loadout
id: LoadoutCommandCMOOuterWinter
category: JobsCommandCMO
- cost: 2
+ cost: 1
requirements:
- !type:CharacterJobRequirement
jobs:
@@ -36,7 +36,7 @@
- type: loadout
id: LoadoutCommandCMOOuterLab
category: JobsCommandCMO
- cost: 1
+ cost: 0
requirements:
- !type:CharacterJobRequirement
jobs:
@@ -47,7 +47,7 @@
- type: loadout
id: LoadoutCommandCMOHatBeret
category: JobsCommandCMO
- cost: 1
+ cost: 0
requirements:
- !type:CharacterJobRequirement
jobs:
@@ -58,7 +58,7 @@
- type: loadout
id: LoadoutCommandCMOShoesBootsWinter
category: JobsCommandCMO
- cost: 1
+ cost: 0
exclusive: true
requirements:
- !type:CharacterJobRequirement
diff --git a/Resources/Prototypes/Loadouts/Jobs/Heads/headOfPersonnel.yml b/Resources/Prototypes/Loadouts/Jobs/Heads/headOfPersonnel.yml
index 44b77d3acd..d17a31bb65 100644
--- a/Resources/Prototypes/Loadouts/Jobs/Heads/headOfPersonnel.yml
+++ b/Resources/Prototypes/Loadouts/Jobs/Heads/headOfPersonnel.yml
@@ -1,7 +1,7 @@
- type: loadout
id: LoadoutCommandHOPNeckMantle
category: JobsCommandHOP
- cost: 2
+ cost: 0
exclusive: true
requirements:
- !type:CharacterJobRequirement
@@ -13,7 +13,7 @@
- type: loadout
id: LoadoutCommandHOPNeckCloak
category: JobsCommandHOP
- cost: 2
+ cost: 0
exclusive: true
requirements:
- !type:CharacterJobRequirement
@@ -25,7 +25,7 @@
- type: loadout
id: LoadoutCommandHOPJumpsuitTurtleneckBoatswain
category: JobsCommandHOP
- cost: 2
+ cost: 0
exclusive: true
requirements:
- !type:CharacterJobRequirement
@@ -37,7 +37,7 @@
- type: loadout
id: LoadoutCommandHOPJumpsuitMess
category: JobsCommandHOP
- cost: 2
+ cost: 0
exclusive: true
requirements:
- !type:CharacterJobRequirement
@@ -49,7 +49,7 @@
- type: loadout
id: LoadoutCommandHOPJumpskirtMess
category: JobsCommandHOP
- cost: 2
+ cost: 0
exclusive: true
requirements:
- !type:CharacterJobRequirement
@@ -61,7 +61,7 @@
- type: loadout
id: LoadoutcommandHOPOuterCoatFormal
category: JobsCommandHOP
- cost: 2
+ cost: 0
requirements:
- !type:CharacterJobRequirement
jobs:
@@ -72,7 +72,7 @@
- type: loadout
id: LoadoutCommandHOPBackIan
category: JobsCommandHOP
- cost: 4
+ cost: 2
requirements:
- !type:CharacterJobRequirement
jobs:
@@ -83,7 +83,7 @@
- type: loadout
id: LoadoutCommandHOPHatCap
category: JobsCommandHOP
- cost: 1
+ cost: 0
requirements:
- !type:CharacterJobRequirement
jobs:
@@ -94,7 +94,7 @@
- type: loadout
id: LoadoutCommandHOPShoesBootsWinter
category: JobsCommandHOP
- cost: 1
+ cost: 0
exclusive: true
requirements:
- !type:CharacterJobRequirement
@@ -106,7 +106,7 @@
- type: loadout
id: LoadoutCommandHOPBedsheetIan
category: JobsCommandHOP
- cost: 2
+ cost: 0
exclusive: true
requirements:
- !type:CharacterJobRequirement
diff --git a/Resources/Prototypes/Loadouts/Jobs/Heads/headOfSecurity.yml b/Resources/Prototypes/Loadouts/Jobs/Heads/headOfSecurity.yml
index 89e36caed4..6e53c0195e 100644
--- a/Resources/Prototypes/Loadouts/Jobs/Heads/headOfSecurity.yml
+++ b/Resources/Prototypes/Loadouts/Jobs/Heads/headOfSecurity.yml
@@ -1,7 +1,7 @@
- type: loadout
id: LoadoutCommandHOSNeckMantle
category: JobsCommandHOS
- cost: 2
+ cost: 0
exclusive: true
requirements:
- !type:CharacterJobRequirement
@@ -13,7 +13,7 @@
- type: loadout
id: LoadoutCommandHOSNeckCloak
category: JobsCommandHOS
- cost: 2
+ cost: 0
exclusive: true
requirements:
- !type:CharacterJobRequirement
@@ -25,7 +25,7 @@
- type: loadout
id: LoadoutCommandHOSJumpsuitAlt
category: JobsCommandHOS
- cost: 2
+ cost: 0
exclusive: true
requirements:
- !type:CharacterJobRequirement
@@ -37,7 +37,7 @@
- type: loadout
id: LoadoutCommandHOSJumpsuitBlue
category: JobsCommandHOS
- cost: 2
+ cost: 0
exclusive: true
requirements:
- !type:CharacterJobRequirement
@@ -49,7 +49,7 @@
- type: loadout
id: LoadoutCommandHOSJumpsuitGrey
category: JobsCommandHOS
- cost: 2
+ cost: 0
exclusive: true
requirements:
- !type:CharacterJobRequirement
@@ -61,7 +61,7 @@
- type: loadout
id: LoadoutCommandHOSJumpsuitParade
category: JobsCommandHOS
- cost: 3
+ cost: 0
exclusive: true
requirements:
- !type:CharacterJobRequirement
@@ -73,7 +73,7 @@
- type: loadout
id: LoadoutCommandHOSJumpsuitFormal
category: JobsCommandHOS
- cost: 3
+ cost: 0
exclusive: true
requirements:
- !type:CharacterJobRequirement
@@ -85,7 +85,7 @@
- type: loadout
id: LoadoutCommandHOSJumpskirtAlt
category: JobsCommandHOS
- cost: 2
+ cost: 0
exclusive: true
requirements:
- !type:CharacterJobRequirement
@@ -97,7 +97,7 @@
- type: loadout
id: LoadoutCommandHOSJumpskirtParade
category: JobsCommandHOS
- cost: 3
+ cost: 0
exclusive: true
requirements:
- !type:CharacterJobRequirement
@@ -109,7 +109,7 @@
- type: loadout
id: LoadoutCommandHOSJumpskirtFormal
category: JobsCommandHOS
- cost: 3
+ cost: 0
exclusive: true
requirements:
- !type:CharacterJobRequirement
@@ -121,7 +121,7 @@
- type: loadout
id: LoadoutCommandHOSOuterWinter
category: JobsCommandHOS
- cost: 2
+ cost: 1
requirements:
- !type:CharacterJobRequirement
jobs:
@@ -132,7 +132,7 @@
- type: loadout
id: LoadoutCommandHOSOuterTrench
category: JobsCommandHOS
- cost: 2
+ cost: 1
requirements:
- !type:CharacterJobRequirement
jobs:
@@ -143,7 +143,7 @@
- type: loadout
id: LoadoutCommandHOSHatBeret
category: JobsCommandHOS
- cost: 1
+ cost: 0
requirements:
- !type:CharacterJobRequirement
jobs:
@@ -154,7 +154,7 @@
- type: loadout
id: LoadoutCommandHOSHatHoshat
category: JobsCommandHOS
- cost: 1
+ cost: 0
requirements:
- !type:CharacterJobRequirement
jobs:
@@ -165,7 +165,7 @@
- type: loadout
id: LoadoutCommandHOSShoesBootsWinter
category: JobsCommandHOS
- cost: 1
+ cost: 0
exclusive: true
requirements:
- !type:CharacterJobRequirement
diff --git a/Resources/Prototypes/Loadouts/Jobs/Heads/quarterMaster.yml b/Resources/Prototypes/Loadouts/Jobs/Heads/quarterMaster.yml
index 62d872cea2..8064b3105e 100644
--- a/Resources/Prototypes/Loadouts/Jobs/Heads/quarterMaster.yml
+++ b/Resources/Prototypes/Loadouts/Jobs/Heads/quarterMaster.yml
@@ -14,7 +14,7 @@
- type: loadout
id: LoadoutCommandQMNeckCloak
category: JobsCommandQM
- cost: 2
+ cost: 0
exclusive: true
requirements:
- !type:CharacterJobRequirement
@@ -26,7 +26,7 @@
- type: loadout
id: LoadoutCommandQMUniformTurtleneck
category: JobsCommandQM
- cost: 2
+ cost: 0
exclusive: true
requirements:
- !type:CharacterJobRequirement
@@ -38,7 +38,7 @@
- type: loadout
id: LoadoutCommandQMUniformTurtleneckSkirt
category: JobsCommandQM
- cost: 2
+ cost: 0
exclusive: true
requirements:
- !type:CharacterJobRequirement
@@ -50,7 +50,7 @@
- type: loadout
id: LoadoutCommandQMHeadSoft
category: JobsCommandQM
- cost: 1
+ cost: 0
requirements:
- !type:CharacterJobRequirement
jobs:
@@ -61,7 +61,7 @@
- type: loadout
id: LoadoutCommandQMShoesBootsWinter
category: JobsCommandQM
- cost: 1
+ cost: 0
exclusive: true
requirements:
- !type:CharacterJobRequirement
diff --git a/Resources/Prototypes/Loadouts/Jobs/Heads/researchDirector.yml b/Resources/Prototypes/Loadouts/Jobs/Heads/researchDirector.yml
index 6448f4a151..5d0421fe39 100644
--- a/Resources/Prototypes/Loadouts/Jobs/Heads/researchDirector.yml
+++ b/Resources/Prototypes/Loadouts/Jobs/Heads/researchDirector.yml
@@ -1,53 +1,97 @@
+# Outer
+
- type: loadout
- id: LoadoutCommandRDNeckMantle
+ id: LoadoutCommandRDOuterWinter
category: JobsCommandRD
- cost: 2
+ cost: 1
+ requirements:
+ - !type:CharacterJobRequirement
+ jobs:
+ - ResearchDirector
+ items:
+ - ClothingOuterWinterRD
+
+- type: loadout
+ id: LoadoutCommandRDOuterMysta
+ category: JobsCommandRD
+ cost: 0
+ requirements:
+ - !type:CharacterJobRequirement
+ jobs:
+ - ResearchDirector
+ items:
+ - ClothingOuterCoatRndMysta
+
+# Head
+
+- type: loadout
+ id: LoadoutCommandRDHeadHatBeretMysta
+ category: JobsCommandRD
+ cost: 0
exclusive: true
requirements:
- !type:CharacterJobRequirement
jobs:
- ResearchDirector
items:
- - ClothingNeckMantleRD
+ - ClothingHeadHatBeretMysta
- type: loadout
- id: LoadoutCommandRDNeckCloak
+ id: LoadoutCommandRDHeadHoodMysta
category: JobsCommandRD
- cost: 2
+ cost: 0
exclusive: true
requirements:
- !type:CharacterJobRequirement
jobs:
- ResearchDirector
items:
- - ClothingNeckCloakRd
+ - ClothingHeadHoodMysta
+
+# Neck
- type: loadout
- id: LoadoutCommandRDOuterWinter
+ id: LoadoutCommandRDNeckMantle
category: JobsCommandRD
- cost: 2
+ cost: 0
+ exclusive: true
requirements:
- !type:CharacterJobRequirement
jobs:
- ResearchDirector
items:
- - ClothingOuterWinterRD
+ - ClothingNeckMantleRD
- type: loadout
- id: LoadoutCommandRDOuterMysta
+ id: LoadoutCommandRDNeckCloak
category: JobsCommandRD
- cost: 2
+ cost: 0
+ exclusive: true
requirements:
- !type:CharacterJobRequirement
jobs:
- ResearchDirector
items:
- - ClothingOuterCoatRndMysta
+ - ClothingNeckCloakRd
+
+- type: loadout
+ id: LoadoutCommandRDNeckCloakMystagogue
+ category: JobsCommandRD
+ cost: 0
+ exclusive: true
+ requirements:
+ - !type:CharacterJobRequirement
+ jobs:
+ - ResearchDirector
+ items:
+ - ClothingNeckCloakMystagogue
+
+# Shoes
- type: loadout
id: LoadoutCommandRDShoesBootsWinter
category: JobsCommandRD
- cost: 1
+ cost: 0
exclusive: true
requirements:
- !type:CharacterJobRequirement
diff --git a/Resources/Prototypes/Loadouts/Jobs/cargo.yml b/Resources/Prototypes/Loadouts/Jobs/cargo.yml
index 2bec0b7c0a..4558e362bf 100644
--- a/Resources/Prototypes/Loadouts/Jobs/cargo.yml
+++ b/Resources/Prototypes/Loadouts/Jobs/cargo.yml
@@ -1,10 +1,12 @@
# Cargo technician
- type: loadout
id: LoadoutCargoOuterWinterCargo
- category: JobsAUncategorized
- cost: 2
+ category: JobsCargo
+ cost: 1
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutOuterCargo
- !type:CharacterJobRequirement
jobs:
- CargoTechnician
@@ -13,10 +15,12 @@
- type: loadout
id: LoadoutCargoShoesBootsWinterCargo
- category: JobsAUncategorized
- cost: 1
+ category: JobsCargo
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutShoesCargo
- !type:CharacterJobRequirement
jobs:
- CargoTechnician
@@ -27,10 +31,12 @@
- type: loadout
id: LoadoutCargoOuterWinterMiner
- category: JobsAUncategorized
- cost: 2
+ category: JobsCargo
+ cost: 1
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutOuterCargo
- !type:CharacterJobRequirement
jobs:
- SalvageSpecialist
@@ -39,10 +45,12 @@
- type: loadout
id: LoadoutCargoNeckGoliathCloak
- category: JobsAUncategorized
- cost: 2
+ category: JobsCargo
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutNeckCargo
- !type:CharacterJobRequirement
jobs:
- SalvageSpecialist
diff --git a/Resources/Prototypes/Loadouts/Jobs/engineering.yml b/Resources/Prototypes/Loadouts/Jobs/engineering.yml
index 94f018e583..2bf857c85f 100644
--- a/Resources/Prototypes/Loadouts/Jobs/engineering.yml
+++ b/Resources/Prototypes/Loadouts/Jobs/engineering.yml
@@ -1,9 +1,11 @@
- type: loadout
id: LoadoutEngineeringUniformHazard
- category: JobsAUncategorized
- cost: 2
+ category: JobsEngineering
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsEngineering
- !type:CharacterJobRequirement
jobs:
- StationEngineer
@@ -12,10 +14,12 @@
- type: loadout
id: LoadoutEngineeringOuterHazard
- category: JobsAUncategorized
- cost: 2
+ category: JobsEngineering
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutOuterEngineering
- !type:CharacterJobRequirement
jobs:
- StationEngineer
@@ -24,10 +28,12 @@
- type: loadout
id: LoadoutEngineeringUniformJumpskirtSenior
- category: JobsAUncategorized
- cost: 2
+ category: JobsEngineering
+ cost: 1
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsEngineering
- !type:CharacterJobRequirement
jobs:
- StationEngineer
@@ -45,10 +51,12 @@
- type: loadout
id: LoadoutEngineeringUniformJumpsuitSenior
- category: JobsAUncategorized
- cost: 2
+ category: JobsEngineering
+ cost: 1
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsEngineering
- !type:CharacterJobRequirement
jobs:
- StationEngineer
@@ -66,10 +74,12 @@
- type: loadout
id: LoadoutEngineeringChickenSuit # :)
- category: JobsAUncategorized
- cost: 3
+ category: JobsEngineering
+ cost: 1
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutOuterEngineering
- !type:CharacterJobRequirement
jobs:
- AtmosphericTechnician
@@ -79,10 +89,12 @@
- type: loadout
id: LoadoutEngineeringEyesMeson
- category: JobsAUncategorized
- cost: 2
+ category: JobsEngineering
+ cost: 1
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutEyesEngineering
- !type:CharacterJobRequirement
jobs:
- StationEngineer
@@ -92,10 +104,12 @@
- type: loadout
id: LoadoutEngineeringHeadBeret
- category: JobsAUncategorized
- cost: 1
+ category: JobsEngineering
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutHeadEngineering
- !type:CharacterJobRequirement
jobs:
- StationEngineer
@@ -106,10 +120,12 @@
- type: loadout
id: LoadoutEngineeringHeadHardhatBlue
- category: JobsAUncategorized
- cost: 2
+ category: JobsEngineering
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutHeadEngineering
- !type:CharacterJobRequirement
jobs:
- StationEngineer
@@ -119,10 +135,12 @@
- type: loadout
id: LoadoutEngineeringHeadHardhatOrange
- category: JobsAUncategorized
- cost: 2
+ category: JobsEngineering
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutHeadEngineering
- !type:CharacterJobRequirement
jobs:
- StationEngineer
@@ -132,10 +150,12 @@
- type: loadout
id: LoadoutEngineeringHeadHardhatYellow
- category: JobsAUncategorized
- cost: 2
+ category: JobsEngineering
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutHeadEngineering
- !type:CharacterJobRequirement
jobs:
- StationEngineer
@@ -145,10 +165,12 @@
- type: loadout
id: LoadoutEngineeringHeadHardhatWhite
- category: JobsAUncategorized
- cost: 2
+ category: JobsEngineering
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutHeadEngineering
- !type:CharacterJobRequirement
jobs:
- StationEngineer
@@ -158,10 +180,12 @@
- type: loadout
id: LoadoutEngineeringHeadHardhatRed
- category: JobsAUncategorized
- cost: 2
+ category: JobsEngineering
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutHeadEngineering
- !type:CharacterJobRequirement
jobs:
- StationEngineer
diff --git a/Resources/Prototypes/Loadouts/Jobs/medical.yml b/Resources/Prototypes/Loadouts/Jobs/medical.yml
index 33d6ff36da..6a2d5fb9d2 100644
--- a/Resources/Prototypes/Loadouts/Jobs/medical.yml
+++ b/Resources/Prototypes/Loadouts/Jobs/medical.yml
@@ -1,9 +1,11 @@
- type: loadout
id: LoadoutMedicalGlovesNitrile
- category: JobsAUncategorized
- cost: 1
+ category: JobsMedical
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutGlovesMedical
- !type:CharacterJobRequirement
jobs:
- MedicalDoctor
@@ -16,10 +18,12 @@
- type: loadout
id: LoadoutMedicalOuterLabcoat
- category: JobsAUncategorized
- cost: 2
+ category: JobsMedical
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutOuterMedical
- !type:CharacterJobRequirement
jobs:
- MedicalDoctor
@@ -29,10 +33,12 @@
- type: loadout
id: LoadoutMedicalNeckStethoscope
- category: JobsAUncategorized
- cost: 1
+ category: JobsMedical
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutNeckMedical
- !type:CharacterJobRequirement
jobs:
- MedicalDoctor
@@ -43,10 +49,12 @@
- type: loadout
id: LoadoutMedicalUniformScrubsBlue
- category: JobsAUncategorized
- cost: 2
+ category: JobsMedical
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsMedical
- !type:CharacterJobRequirement
jobs:
- MedicalDoctor
@@ -58,10 +66,12 @@
- type: loadout
id: LoadoutMedicalUniformScrubsGreen
- category: JobsAUncategorized
- cost: 2
+ category: JobsMedical
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsMedical
- !type:CharacterJobRequirement
jobs:
- MedicalDoctor
@@ -73,10 +83,12 @@
- type: loadout
id: LoadoutMedicalUniformScrubsPurple
- category: JobsAUncategorized
- cost: 2
+ category: JobsMedical
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsMedical
- !type:CharacterJobRequirement
jobs:
- MedicalDoctor
@@ -88,10 +100,12 @@
- type: loadout
id: LoadoutMedicalUniformScrubsCyan
- category: JobsAUncategorized
- cost: 2
+ category: JobsMedical
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsMedical
- !type:CharacterJobRequirement
jobs:
- MedicalDoctor
@@ -103,10 +117,12 @@
- type: loadout
id: LoadoutMedicalUniformScrubsBlack
- category: JobsAUncategorized
- cost: 2
+ category: JobsMedical
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsMedical
- !type:CharacterJobRequirement
jobs:
- MedicalDoctor
@@ -118,10 +134,12 @@
- type: loadout
id: LoadoutMedicalUniformScrubsPink
- category: JobsAUncategorized
- cost: 2
+ category: JobsMedical
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsMedical
- !type:CharacterJobRequirement
jobs:
- MedicalDoctor
@@ -133,10 +151,12 @@
- type: loadout
id: LoadoutMedicalUniformScrubsCybersun
- category: JobsAUncategorized
- cost: 3
+ category: JobsMedical
+ cost: 1
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsMedical
- !type:CharacterJobRequirement
jobs:
- MedicalDoctor
@@ -147,10 +167,12 @@
- type: loadout
id: LoadoutMedicalOuterCybersunWindbreaker
- category: JobsAUncategorized
- cost: 5
+ category: JobsMedical
+ cost: 3
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutOuterMedical
- !type:CharacterJobRequirement
jobs:
- MedicalDoctor
@@ -161,10 +183,12 @@
- type: loadout
id: LoadoutMedicalOuterLabcoatChem
- category: JobsAUncategorized
- cost: 2
+ category: JobsMedical
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutOuterMedical
- !type:CharacterJobRequirement
jobs:
- Chemist
@@ -173,7 +197,7 @@
- type: loadout
id: LoadoutMedicalItemHandLabeler
- category: JobsAUncategorized
+ category: JobsMedical
exclusive: true
requirements:
- !type:CharacterJobRequirement
@@ -184,10 +208,12 @@
- type: loadout
id: LoadoutMedicalUniformParamedicJumpsuit
- category: JobsAUncategorized
- cost: 2
+ category: JobsMedical
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsMedical
- !type:CharacterJobRequirement
jobs:
- Paramedic
@@ -196,10 +222,12 @@
- type: loadout
id: LoadoutMedicalUniformParamedicJumpskirt
- category: JobsAUncategorized
- cost: 2
+ category: JobsMedical
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsMedical
- !type:CharacterJobRequirement
jobs:
- Paramedic
@@ -208,10 +236,12 @@
- type: loadout
id: LoadoutMedicalUniformJumpskirtSenior
- category: JobsAUncategorized
- cost: 2
+ category: JobsMedical
+ cost: 1
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsMedical
- !type:CharacterJobRequirement
jobs:
- MedicalDoctor
@@ -232,10 +262,12 @@
- type: loadout
id: LoadoutMedicalUniformJumpsuitSenior
- category: JobsAUncategorized
- cost: 2
+ category: JobsMedical
+ cost: 1
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsMedical
- !type:CharacterJobRequirement
jobs:
- MedicalDoctor
@@ -256,10 +288,12 @@
- type: loadout
id: LoadoutMedicalHeadNurse
- category: JobsAUncategorized
- cost: 2
+ category: JobsMedical
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutHeadMedical
- !type:CharacterJobRequirement
jobs:
- MedicalDoctor
@@ -268,10 +302,12 @@
- type: loadout
id: LoadoutMedicalHeadBeretSeniorPhysician
- category: JobsAUncategorized
- cost: 2
+ category: JobsMedical
+ cost: 1
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutHeadMedical
- !type:CharacterJobRequirement
jobs:
- MedicalDoctor
@@ -292,10 +328,12 @@
- type: loadout
id: LoadoutMedicalHeadSurgcapBlue
- category: JobsAUncategorized
- cost: 2
+ category: JobsMedical
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutHeadMedical
- !type:CharacterJobRequirement
jobs:
- MedicalDoctor
@@ -307,10 +345,12 @@
- type: loadout
id: LoadoutMedicalHeadSurgcapPurple
- category: JobsAUncategorized
- cost: 2
+ category: JobsMedical
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutHeadMedical
- !type:CharacterJobRequirement
jobs:
- MedicalDoctor
@@ -322,10 +362,12 @@
- type: loadout
id: LoadoutMedicalHeadSurgcapGreen
- category: JobsAUncategorized
- cost: 2
+ category: JobsMedical
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutHeadMedical
- !type:CharacterJobRequirement
jobs:
- MedicalDoctor
@@ -337,10 +379,12 @@
- type: loadout
id: LoadoutMedicalHeadSurgcapCyan
- category: JobsAUncategorized
- cost: 2
+ category: JobsMedical
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutHeadMedical
- !type:CharacterJobRequirement
jobs:
- MedicalDoctor
@@ -352,10 +396,12 @@
- type: loadout
id: LoadoutMedicalHeadSurgcapBlack
- category: JobsAUncategorized
- cost: 2
+ category: JobsMedical
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutHeadMedical
- !type:CharacterJobRequirement
jobs:
- MedicalDoctor
@@ -367,10 +413,12 @@
- type: loadout
id: LoadoutMedicalHeadSurgcapPink
- category: JobsAUncategorized
- cost: 2
+ category: JobsMedical
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutHeadMedical
- !type:CharacterJobRequirement
jobs:
- MedicalDoctor
@@ -382,10 +430,12 @@
- type: loadout
id: LoadoutMedicalHeadSurgcapWhite
- category: JobsAUncategorized
- cost: 2
+ category: JobsMedical
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutHeadMedical
- !type:CharacterJobRequirement
jobs:
- MedicalDoctor
@@ -397,10 +447,12 @@
- type: loadout
id: LoadoutMedicalHeadSurgcapCybersun
- category: JobsAUncategorized
- cost: 3
+ category: JobsMedical
+ cost: 1
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutHeadMedical
- !type:CharacterJobRequirement
jobs:
- MedicalDoctor
@@ -411,10 +463,12 @@
- type: loadout
id: LoadoutMedicalEyesHudMedical
- category: JobsAUncategorized
- cost: 2
+ category: JobsMedical
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutEyesMedical
- !type:CharacterJobRequirement
jobs:
- MedicalDoctor
@@ -427,10 +481,12 @@
- type: loadout
id: LoadoutMedicalEyesEyepatchHudMedical
- category: JobsAUncategorized
- cost: 2
+ category: JobsMedical
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutEyesMedical
- !type:CharacterJobRequirement
jobs:
- MedicalDoctor
@@ -443,10 +499,12 @@
- type: loadout
id: LoadoutMedicalEyesHudMedicalPrescription
- category: JobsAUncategorized
- cost: 2
+ category: JobsMedical
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutEyesMedical
- !type:CharacterJobRequirement
jobs:
- MedicalDoctor
@@ -462,10 +520,12 @@
- type: loadout
id: LoadoutMedicalEyesGlassesChemical
- category: JobsAUncategorized
- cost: 2
+ category: JobsMedical
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutEyesMedical
- !type:CharacterJobRequirement
jobs:
- Chemist
@@ -474,10 +534,12 @@
- type: loadout
id: LoadoutMedicalBedsheetMedical
- category: JobsAUncategorized
- cost: 2
+ category: JobsMedical
+ cost: 1
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutNeckMedical
- !type:CharacterDepartmentRequirement
departments:
- Medical
@@ -487,10 +549,12 @@
# Chemist PPE gear
- type: loadout
id: LoadoutMedicalUniformJumpsuitChemShirt
- category: JobsAUncategorized
- cost: 2
+ category: JobsMedical
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsMedical
- !type:CharacterJobRequirement
jobs:
- Chemist
@@ -499,10 +563,12 @@
- type: loadout
id: LoadoutMedicalNeckTieChem
- category: JobsAUncategorized
- cost: 1
+ category: JobsMedical
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutNeckMedical
- !type:CharacterJobRequirement
jobs:
- Chemist
@@ -511,10 +577,12 @@
- type: loadout
id: LoadoutMedicalShoesEnclosedChem
- category: JobsAUncategorized
- cost: 1
+ category: JobsMedical
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutShoesMedical
- !type:CharacterJobRequirement
jobs:
- Chemist
@@ -523,10 +591,12 @@
- type: loadout
id: LoadoutMedicalOuterApronChemist
- category: JobsAUncategorized
- cost: 2
+ category: JobsMedical
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutOuterMedical
- !type:CharacterJobRequirement
jobs:
- Chemist
@@ -535,10 +605,12 @@
- type: loadout
id: LoadoutMedicalEyesGlassesChemist
- category: JobsAUncategorized
- cost: 2
+ category: JobsMedical
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutEyesMedical
- !type:CharacterJobRequirement
jobs:
- Chemist
@@ -547,10 +619,12 @@
- type: loadout
id: LoadoutMedicalHandsGlovesChemist
- category: JobsAUncategorized
- cost: 1
+ category: JobsMedical
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutGlovesMedical
- !type:CharacterJobRequirement
jobs:
- Chemist
diff --git a/Resources/Prototypes/Loadouts/Jobs/science.yml b/Resources/Prototypes/Loadouts/Jobs/science.yml
index 8a1a2710c2..9a9526f83f 100644
--- a/Resources/Prototypes/Loadouts/Jobs/science.yml
+++ b/Resources/Prototypes/Loadouts/Jobs/science.yml
@@ -1,9 +1,13 @@
+# Uniforms
+
- type: loadout
id: LoadoutScienceUniformJumpskirtSenior
- category: JobsAUncategorized
- cost: 2
+ category: JobsScience
+ cost: 1
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsScience
- !type:CharacterJobRequirement
jobs:
- Scientist
@@ -15,10 +19,12 @@
- type: loadout
id: LoadoutScienceUniformJumpsuitSenior
- category: JobsAUncategorized
- cost: 2
+ category: JobsScience
+ cost: 1
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsScience
- !type:CharacterJobRequirement
jobs:
- Scientist
@@ -28,12 +34,72 @@
items:
- ClothingUniformJumpsuitSeniorResearcher
+- type: loadout
+ id: LoadoutScienceUniformJumpskirtRoboticist
+ category: JobsScience
+ cost: 1
+ exclusive: true
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsScience
+ - !type:CharacterJobRequirement
+ jobs:
+ - Scientist
+ items:
+ - ClothingUniformJumpskirtRoboticist
+
+- type: loadout
+ id: LoadoutScienceUniformJumpsuitRoboticist
+ category: JobsScience
+ cost: 1
+ exclusive: true
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsScience
+ - !type:CharacterJobRequirement
+ jobs:
+ - Scientist
+ items:
+ - ClothingUniformJumpsuitRoboticist
+
+- type: loadout
+ id: LoadoutScienceUniformJumpsuitMonasticRobeDark
+ category: JobsScience
+ cost: 0
+ exclusive: true
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsScience
+ - !type:CharacterJobRequirement
+ jobs:
+ - Chaplain
+ items:
+ - ClothingUniformJumpsuitMonasticRobeDark
+
+- type: loadout
+ id: LoadoutScienceUniformJumpsuitMonasticRobeLight
+ category: JobsScience
+ cost: 0
+ exclusive: true
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsScience
+ - !type:CharacterJobRequirement
+ jobs:
+ - Chaplain
+ items:
+ - ClothingUniformJumpsuitMonasticRobeLight
+
+# Outer
+
- type: loadout
id: LoadoutScienceOuterCoat
- category: JobsAUncategorized
- cost: 2
+ category: JobsScience
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutOuterScience
- !type:CharacterJobRequirement
jobs:
- Scientist
@@ -44,10 +110,12 @@
- type: loadout
id: LoadoutScienceOuterLabcoat
- category: JobsAUncategorized
- cost: 2
+ category: JobsScience
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutOuterScience
- !type:CharacterJobRequirement
jobs:
- Scientist
@@ -56,12 +124,42 @@
items:
- ClothingOuterCoatLab
+- type: loadout
+ id: LoadoutSciencegOuterCoatRobo
+ category: JobsScience
+ cost: 0
+ exclusive: true
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutOuterScience
+ - !type:CharacterJobRequirement
+ jobs:
+ - Scientist
+ items:
+ - ClothingOuterCoatRobo
+
+- type: loadout
+ id: LoadoutScienceOuterWinterSci
+ category: JobsScience
+ cost: 1
+ exclusive: true
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutOuterScience
+ - !type:CharacterJobRequirement
+ jobs:
+ - Scientist
+ items:
+ - ClothingOuterWinterSci
+
- type: loadout
id: LoadoutScienceOuterLabcoatSeniorResearcher
- category: JobsAUncategorized
- cost: 2
+ category: JobsScience
+ cost: 1
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutOuterScience
- !type:CharacterJobRequirement
jobs:
- Scientist
@@ -73,10 +171,12 @@
- type: loadout
id: LoadoutScienceOuterExplorerLabcoat
- category: JobsAUncategorized
- cost: 2
+ category: JobsScience
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutOuterScience
- !type:CharacterJobRequirement
jobs:
- Scientist
@@ -86,11 +186,208 @@
- ClothingOuterExplorerCoat
- type: loadout
- id: LoadoutScienceHatBeret
- category: JobsAUncategorized
+ id: LoadoutScienceOuterPlagueSuit
+ category: JobsScience
+ cost: 0
+ exclusive: true
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutOuterScience
+ - !type:CharacterJobRequirement
+ jobs:
+ - Chaplain
+ items:
+ - ClothingOuterPlagueSuit
+
+- type: loadout
+ id: LoadoutScienceOuterNunRobe
+ category: JobsScience
+ cost: 0
+ exclusive: true
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutOuterScience
+ - !type:CharacterJobRequirement
+ jobs:
+ - Chaplain
+ items:
+ - ClothingOuterNunRobe
+
+- type: loadout
+ id: LoadoutScienceOuterHoodieBlack
+ category: JobsScience
+ cost: 0
+ exclusive: true
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutOuterScience
+ - !type:CharacterJobRequirement
+ jobs:
+ - Chaplain
+ items:
+ - ClothingOuterHoodieBlack
+
+- type: loadout
+ id: LoadoutScienceOuterHoodieChaplain
+ category: JobsScience
+ cost: 0
+ exclusive: true
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutOuterScience
+ - !type:CharacterJobRequirement
+ jobs:
+ - Chaplain
+ items:
+ - ClothingOuterHoodieChaplain
+
+- type: loadout
+ id: LoadoutScienceOuterWinterCoatMantis
+ category: JobsScience
cost: 1
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutOuterScience
+ - !type:CharacterJobRequirement
+ jobs:
+ - ForensicMantis
+ items:
+ - ClothingOuterWinterCoatMantis
+
+# Gloves
+
+- type: loadout
+ id: LoadoutScienceHandsGlovesColorPurple
+ category: JobsScience
+ cost: 0
+ exclusive: true
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutGlovesScience
+ - !type:CharacterJobRequirement
+ jobs:
+ - Scientist
+ - ResearchDirector
+ items:
+ - ClothingHandsGlovesColorPurple
+
+- type: loadout
+ id: LoadoutScienceHandsGlovesLatex
+ category: JobsScience
+ cost: 0
+ exclusive: true
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutGlovesScience
+ - !type:CharacterJobRequirement
+ jobs:
+ - Scientist
+ - ResearchDirector
+ items:
+ - ClothingHandsGlovesLatex
+
+- type: loadout
+ id: LoadoutScienceHandsGlovesRobohands
+ category: JobsScience
+ cost: 0
+ exclusive: true
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutGlovesScience
+ - !type:CharacterJobRequirement
+ jobs:
+ - Scientist
+ - ResearchDirector
+ items:
+ - ClothingHandsGlovesRobohands
+
+# Neck
+
+- type: loadout
+ id: LoadoutScienceNeckTieSci
+ category: JobsScience
+ cost: 0
+ exclusive: true
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutNeckScience
+ - !type:CharacterJobRequirement
+ jobs:
+ - Scientist
+ - ResearchDirector
+ items:
+ - ClothingNeckTieSci
+
+- type: loadout
+ id: LoadoutScienceNeckScarfStripedPurple
+ category: JobsScience
+ cost: 0
+ exclusive: true
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutNeckScience
+ - !type:CharacterJobRequirement
+ jobs:
+ - Scientist
+ - ResearchDirector
+ items:
+ - ClothingNeckScarfStripedPurple
+
+- type: loadout
+ id: LoadoutScienceNeckStoleChaplain
+ category: JobsScience
+ cost: 0
+ exclusive: true
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutNeckScience
+ - !type:CharacterJobRequirement
+ jobs:
+ - Chaplain
+ items:
+ - ClothingNeckStoleChaplain
+
+- type: loadout
+ id: LoadoutScienceNeckScarfStripedBlack
+ category: JobsScience
+ cost: 0
+ exclusive: true
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutNeckScience
+ - !type:CharacterJobRequirement
+ jobs:
+ - Chaplain
+ items:
+ - ClothingNeckScarfStripedBlack
+
+# Mask
+
+- type: loadout
+ id: LoadoutScienceMaskPlague
+ category: JobsScience
+ cost: 0
+ exclusive: true
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutMaskScience
+ - !type:CharacterJobRequirement
+ jobs:
+ - Chaplain
+ items:
+ - ClothingMaskPlague
+
+# Head
+
+- type: loadout
+ id: LoadoutScienceHeadHatBeret
+ category: JobsScience
+ cost: 0
+ exclusive: true
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutHeadScience
- !type:CharacterJobRequirement
jobs:
- Scientist
@@ -99,12 +396,86 @@
items:
- ClothingHeadHatBeretRND
+- type: loadout
+ id: LoadoutScienceHeadHatFez
+ category: JobsScience
+ cost: 0
+ exclusive: true
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutHeadScience
+ - !type:CharacterJobRequirement
+ jobs:
+ - Chaplain
+ items:
+ - ClothingHeadHatFez
+
+- type: loadout
+ id: LoadoutScienceHeadHatHoodNunHood
+ category: JobsScience
+ cost: 0
+ exclusive: true
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutHeadScience
+ - !type:CharacterJobRequirement
+ jobs:
+ - Chaplain
+ items:
+ - ClothingHeadHatHoodNunHood
+
+- type: loadout
+ id: LoadoutScienceHeadHatPlaguedoctor
+ category: JobsScience
+ cost: 0
+ exclusive: true
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutHeadScience
+ - !type:CharacterJobRequirement
+ jobs:
+ - Chaplain
+ items:
+ - ClothingHeadHatPlaguedoctor
+
+- type: loadout
+ id: LoadoutScienceHeadHatWitch
+ category: JobsScience
+ cost: 0
+ exclusive: true
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutHeadScience
+ - !type:CharacterJobRequirement
+ jobs:
+ - Chaplain
+ items:
+ - ClothingHeadHatWitch
+
+- type: loadout
+ id: LoadoutScienceHeadHatWitch1
+ category: JobsScience
+ cost: 0
+ exclusive: true
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutHeadScience
+ - !type:CharacterJobRequirement
+ jobs:
+ - Chaplain
+ items:
+ - ClothingHeadHatWitch1
+
+# Eyes
+
- type: loadout
id: LoadoutScienceEyesHudDiagnostic
- category: JobsAUncategorized
- cost: 3
+ category: JobsScience
+ cost: 1
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutEyesScience
- !type:CharacterJobRequirement
jobs:
- Scientist
@@ -115,10 +486,12 @@
- type: loadout
id: LoadoutScienceEyesEyepatchHudDiag
- category: JobsAUncategorized
- cost: 3
+ category: JobsScience
+ cost: 1
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutEyesScience
- !type:CharacterJobRequirement
jobs:
- Scientist
@@ -127,14 +500,35 @@
items:
- ClothingEyesEyepatchHudDiag
+# Shoes
+
+- type: loadout
+ id: LoadoutScienceShoesBootsWinterSci
+ category: JobsScience
+ cost: 0
+ exclusive: true
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutShoesScience
+ - !type:CharacterJobRequirement
+ jobs:
+ - Scientist
+ - ResearchAssistant
+ - ResearchDirector
+ items:
+ - ClothingShoesBootsWinterSci
+
# Robes
+
- type: loadout
id: LoadoutOuterRobeTechPriest
category: Outer
- cost: 2
+ cost: 0
items:
- ClothingOuterRobeTechPriest
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutOuterScience
- !type:CharacterJobRequirement
jobs:
- Scientist
@@ -144,11 +538,13 @@
- type: loadout
id: LoadoutHeadHoodTechPriest
category: Head
- cost: 1
+ cost: 0
exclusive: true
items:
- ClothingHeadTechPriest
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutHeadScience
- !type:CharacterJobRequirement
jobs:
- Scientist
diff --git a/Resources/Prototypes/Loadouts/Jobs/security.yml b/Resources/Prototypes/Loadouts/Jobs/security.yml
index 13d11b13fa..db11903313 100644
--- a/Resources/Prototypes/Loadouts/Jobs/security.yml
+++ b/Resources/Prototypes/Loadouts/Jobs/security.yml
@@ -1,10 +1,12 @@
# Uniforms
- type: loadout
id: LoadoutSecurityUniformJumpsuitBlue
- category: JobsAUncategorized
- cost: 1
+ category: JobsSecurity
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsSecurity
- !type:CharacterDepartmentRequirement
departments:
- Security
@@ -13,10 +15,12 @@
- type: loadout
id: LoadoutSecurityUniformJumpsuitGrey
- category: JobsAUncategorized
- cost: 1
+ category: JobsSecurity
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsSecurity
- !type:CharacterDepartmentRequirement
departments:
- Security
@@ -25,10 +29,12 @@
- type: loadout
id: LoadoutSecurityUniformJumpskirtGrey
- category: JobsAUncategorized
- cost: 1
+ category: JobsSecurity
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsSecurity
- !type:CharacterDepartmentRequirement
departments:
- Security
@@ -37,10 +43,12 @@
- type: loadout
id: LoadoutSecurityUniformJumpskirtBlue
- category: JobsAUncategorized
- cost: 1
+ category: JobsSecurity
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsSecurity
- !type:CharacterDepartmentRequirement
departments:
- Security
@@ -49,10 +57,12 @@
- type: loadout
id: LoadoutSecurityUniformJumpskirtSenior
- category: JobsAUncategorized
- cost: 2
+ category: JobsSecurity
+ cost: 1
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsSecurity
- !type:CharacterJobRequirement
jobs:
- SecurityOfficer
@@ -73,10 +83,12 @@
- type: loadout
id: LoadoutSecurityUniformJumpsuitSenior
- category: JobsAUncategorized
- cost: 2
+ category: JobsSecurity
+ cost: 1
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsSecurity
- !type:CharacterJobRequirement
jobs:
- SecurityOfficer
@@ -97,10 +109,12 @@
- type: loadout
id: LoadoutUniformJumpsuitWardenBlue
- category: JobsAUncategorized
- cost: 2
+ category: JobsSecurity
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsSecurity
- !type:CharacterJobRequirement
jobs:
- Warden
@@ -109,10 +123,12 @@
- type: loadout
id: LoadoutUniformJumpsuitWardenGrey
- category: JobsAUncategorized
- cost: 2
+ category: JobsSecurity
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsSecurity
- !type:CharacterJobRequirement
jobs:
- Warden
@@ -121,10 +137,12 @@
- type: loadout
id: LoadoutUniformJumpskirtWardenBlue
- category: JobsAUncategorized
- cost: 2
+ category: JobsSecurity
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsSecurity
- !type:CharacterJobRequirement
jobs:
- Warden
@@ -133,10 +151,12 @@
- type: loadout
id: LoadoutUniformJumpskirtWardenGrey
- category: JobsAUncategorized
- cost: 2
+ category: JobsSecurity
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsSecurity
- !type:CharacterJobRequirement
jobs:
- Warden
@@ -145,10 +165,12 @@
- type: loadout
id: LoadoutUniformJumpskirtHoSBlue
- category: JobsAUncategorized
- cost: 2
+ category: JobsSecurity
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsSecurity
- !type:CharacterJobRequirement
jobs:
- HeadOfSecurity
@@ -157,10 +179,12 @@
- type: loadout
id: LoadoutUniformJumpskirtHoSGrey
- category: JobsAUncategorized
- cost: 2
+ category: JobsSecurity
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsSecurity
- !type:CharacterJobRequirement
jobs:
- HeadOfSecurity
@@ -169,10 +193,12 @@
- type: loadout
id: LoadoutUniformJumpsuitSecFormal
- category: JobsAUncategorized
- cost: 1
+ category: JobsSecurity
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsSecurity
- !type:CharacterDepartmentRequirement
departments:
- Security
@@ -181,10 +207,12 @@
- type: loadout
id: LoadoutUniformJumpsuitSecSummer
- category: JobsAUncategorized
- cost: 1
+ category: JobsSecurity
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsSecurity
- !type:CharacterDepartmentRequirement
departments:
- Security
@@ -194,10 +222,12 @@
# Mask
- type: loadout
id: LoadoutSecurityMaskGasSwat
- category: JobsAUncategorized
- cost: 2
+ category: JobsSecurity
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutMaskSecurity
- !type:CharacterJobRequirement
jobs:
- Warden
@@ -208,9 +238,11 @@
# Shoes
- type: loadout
id: LoadoutSecurityShoesJackboots
- category: JobsAUncategorized
- cost: 1
+ category: JobsSecurity
+ cost: 0
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutShoesSecurity
- !type:CharacterDepartmentRequirement
departments:
- Security
@@ -219,9 +251,11 @@
- type: loadout
id: LoadoutClothingShoesBootsCombat
- category: JobsAUncategorized
- cost: 1
+ category: JobsSecurity
+ cost: 0
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutShoesSecurity
- !type:CharacterDepartmentRequirement
departments:
- Security
@@ -231,10 +265,12 @@
# Eyes
- type: loadout
id: LoadoutSecurityEyesHudSecurity
- category: JobsAUncategorized
+ category: JobsSecurity
cost: 1
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutEyesSecurity
- !type:CharacterDepartmentRequirement
departments:
- Security
@@ -243,10 +279,12 @@
- type: loadout
id: ClothingEyesGlassesSunglasses
- category: JobsAUncategorized
- cost: 1
+ category: JobsSecurity
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutEyesSecurity
- !type:CharacterDepartmentRequirement
departments:
- Security
@@ -255,10 +293,12 @@
- type: loadout
id: LoadoutSecurityEyesEyepatchHudSecurity
- category: JobsAUncategorized
+ category: JobsSecurity
cost: 1
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutEyesSecurity
- !type:CharacterDepartmentRequirement
departments:
- Security
@@ -267,10 +307,12 @@
- type: loadout
id: LoadoutSecurityEyesHudSecurityPrescription
- category: JobsAUncategorized
+ category: JobsSecurity
cost: 1
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutEyesSecurity
- !type:CharacterDepartmentRequirement
departments:
- Security
@@ -282,10 +324,12 @@
- type: loadout
id: LoadoutClothingEyesGlassesSecurity
- category: JobsAUncategorized
- cost: 4
+ category: JobsSecurity
+ cost: 2
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutEyesSecurity
- !type:CharacterDepartmentRequirement
departments:
- Security
@@ -298,10 +342,12 @@
# Head
- type: loadout
id: LoadoutSecurityHeadHatBeret
- category: JobsAUncategorized
- cost: 1
+ category: JobsSecurity
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutHeadSecurity
- !type:CharacterDepartmentRequirement
departments:
- Security
@@ -310,10 +356,12 @@
- type: loadout
id: LoadoutClothingHeadHelmetBasic
- category: JobsAUncategorized
- cost: 2
+ category: JobsSecurity
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutHeadSecurity
- !type:CharacterDepartmentRequirement
departments:
- Security
@@ -322,10 +370,12 @@
- type: loadout
id: LoadoutClothingHeadHatBeretBrigmedic
- category: JobsAUncategorized
- cost: 1
+ category: JobsSecurity
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutHeadSecurity
- !type:CharacterJobRequirement
jobs:
- Brigmedic
@@ -334,10 +384,12 @@
- type: loadout
id: LoadoutClothingHeadHatBeretCorpsman
- category: JobsAUncategorized
- cost: 1
+ category: JobsSecurity
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutHeadSecurity
- !type:CharacterJobRequirement
jobs:
- Brigmedic
@@ -346,10 +398,12 @@
- type: loadout
id: LoadoutClothingHeadHatBeretWarden
- category: JobsAUncategorized
- cost: 1
+ category: JobsSecurity
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutHeadSecurity
- !type:CharacterJobRequirement
jobs:
- Warden
@@ -358,10 +412,12 @@
- type: loadout
id: LoadoutClothingHeadHatBeretHoS
- category: JobsAUncategorized
- cost: 1
+ category: JobsSecurity
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutHeadSecurity
- !type:CharacterJobRequirement
jobs:
- HeadOfSecurity
@@ -370,9 +426,11 @@
- type: loadout
id: LoadoutSecurityHeadHelmetInsulated
- category: JobsAUncategorized
- cost: 2
+ category: JobsSecurity
+ cost: 1
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutHeadSecurity
- !type:CharacterDepartmentRequirement
departments:
- Security
@@ -382,10 +440,12 @@
# Belt
- type: loadout
id: LoadoutSecurityBeltWebbing
- category: JobsAUncategorized
- cost: 1
+ category: JobsSecurity
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutBeltSecurity
- !type:CharacterDepartmentRequirement
departments:
- Security
@@ -394,10 +454,12 @@
- type: loadout
id: LoadoutClothingBeltCorpsmanWebbing
- category: JobsAUncategorized
- cost: 1
+ category: JobsSecurity
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutBeltSecurity
- !type:CharacterJobRequirement
jobs:
- Brigmedic
@@ -406,10 +468,12 @@
- type: loadout
id: LoadoutClothingBeltSecurity
- category: JobsAUncategorized
- cost: 1
+ category: JobsSecurity
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutBeltSecurity
- !type:CharacterDepartmentRequirement
departments:
- Security
@@ -420,22 +484,28 @@
- type: loadout
id: LoadoutClothingHandsGlovesNitrile
- category: JobsAUncategorized
- cost: 1
+ category: JobsSecurity
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutGlovesSecurity
- !type:CharacterJobRequirement
jobs:
- Brigmedic
items:
- ClothingHandsGlovesNitrile
+# Outerwear
+
- type: loadout
id: LoadoutClothingOuterArmorPlateCarrier
- category: JobsAUncategorized
- cost: 2
+ category: JobsSecurity
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutOuterSecurity
- !type:CharacterDepartmentRequirement
departments:
- Security
@@ -444,10 +514,12 @@
- type: loadout
id: LoadoutClothingOuterArmorDuraVest
- category: JobsAUncategorized
- cost: 2
+ category: JobsSecurity
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutOuterSecurity
- !type:CharacterDepartmentRequirement
departments:
- Security
@@ -456,10 +528,12 @@
- type: loadout
id: LoadoutClothingOuterCoatDetective
- category: JobsAUncategorized
- cost: 2
+ category: JobsSecurity
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutOuterSecurity
- !type:CharacterJobRequirement
jobs:
- Detective
@@ -468,10 +542,12 @@
- type: loadout
id: LoadoutOuterVestDetective
- category: JobsAUncategorized
- cost: 2
+ category: JobsSecurity
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutOuterSecurity
- !type:CharacterJobRequirement
jobs:
- Detective
@@ -480,10 +556,12 @@
- type: loadout
id: LoadoutClothingOuterCoatWarden
- category: JobsAUncategorized
- cost: 2
+ category: JobsSecurity
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutOuterSecurity
- !type:CharacterJobRequirement
jobs:
- Warden
@@ -492,10 +570,12 @@
- type: loadout
id: LoadoutClothingOuterCoatHoSTrench
- category: JobsAUncategorized
- cost: 2
+ category: JobsSecurity
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutOuterSecurity
- !type:CharacterJobRequirement
jobs:
- HeadOfSecurity
@@ -504,10 +584,12 @@
- type: loadout
id: LoadoutClothingOuterWinterHoS
- category: JobsAUncategorized
- cost: 2
+ category: JobsSecurity
+ cost: 1
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutOuterSecurity
- !type:CharacterJobRequirement
jobs:
- HeadOfSecurity
@@ -517,10 +599,12 @@
# Neck
- type: loadout
id: LoadoutClothingNeckCloakHos
- category: JobsAUncategorized
- cost: 1
+ category: JobsSecurity
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutNeckSecurity
- !type:CharacterJobRequirement
jobs:
- HeadOfSecurity
@@ -529,10 +613,12 @@
- type: loadout
id: LoadoutClothingNeckMantleHOS
- category: JobsAUncategorized
- cost: 1
+ category: JobsSecurity
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutNeckSecurity
- !type:CharacterJobRequirement
jobs:
- HeadOfSecurity
@@ -541,23 +627,26 @@
- type: loadout
id: LoadoutBedsheetBrigmedic
- category: JobsAUncategorized
- cost: 1
+ category: JobsSecurity
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutNeckSecurity
- !type:CharacterJobRequirement
jobs:
- Brigmedic
items:
- BedsheetBrigmedic
-
# Equipment
- type: loadout
id: LoadoutSecurityCombatKnife
- category: JobsAUncategorized
- cost: 2
+ category: JobsSecurity
+ cost: 1
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutEquipmentSecurity
- !type:CharacterDepartmentRequirement
departments:
- Security
@@ -566,7 +655,7 @@
- type: loadout
id: LoadoutSecurityFlash
- category: JobsAUncategorized
+ category: JobsSecurity
cost: 1
requirements:
- !type:CharacterDepartmentRequirement
@@ -577,8 +666,8 @@
- type: loadout
id: LoadoutSecurityDisabler
- category: JobsAUncategorized
- cost: 2
+ category: JobsSecurity
+ cost: 1
requirements:
- !type:CharacterDepartmentRequirement
departments:
@@ -588,8 +677,8 @@
- type: loadout
id: LoadoutMagazinePistolRubber
- category: JobsAUncategorized
- cost: 2
+ category: JobsSecurity
+ cost: 1
requirements:
- !type:CharacterDepartmentRequirement
departments:
@@ -599,8 +688,8 @@
- type: loadout
id: LoadoutSpeedLoaderMagnumRubber
- category: JobsAUncategorized
- cost: 2
+ category: JobsSecurity
+ cost: 1
exclusive: true
requirements:
- !type:CharacterJobRequirement
@@ -613,7 +702,7 @@
# # Species
# - type: loadout
# id: LoadoutSecurityEquipmentTruncheon
-# category: JobsAUncategorized
+# category: JobsSecurity
# cost: 8
# requirements:
# - !type:CharacterJobRequirement
diff --git a/Resources/Prototypes/Loadouts/Jobs/service.yml b/Resources/Prototypes/Loadouts/Jobs/service.yml
index 815138e393..bdfa3d8165 100644
--- a/Resources/Prototypes/Loadouts/Jobs/service.yml
+++ b/Resources/Prototypes/Loadouts/Jobs/service.yml
@@ -1,10 +1,12 @@
# Clown
- type: loadout
id: LoadoutServiceClownOutfitJester
- category: JobsAUncategorized
- cost: 3
+ category: JobsServiceUncategorized
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsService
- !type:CharacterJobRequirement
jobs:
- Clown
@@ -15,10 +17,12 @@
- type: loadout
id: LoadoutServiceClownOutfitJesterAlt
- category: JobsAUncategorized
- cost: 3
+ category: JobsServiceUncategorized
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsService
- !type:CharacterJobRequirement
jobs:
- Clown
@@ -29,10 +33,12 @@
- type: loadout
id: LoadoutServiceClownOuterWinter
- category: JobsAUncategorized
- cost: 2
+ category: JobsServiceUncategorized
+ cost: 1
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutOuterService
- !type:CharacterJobRequirement
jobs:
- Clown
@@ -41,10 +47,12 @@
- type: loadout
id: LoadoutServiceClownOuterClownPriest
- category: JobsAUncategorized
- cost: 2
+ category: JobsServiceUncategorized
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutOuterService
- !type:CharacterJobRequirement
jobs:
- Clown
@@ -53,10 +61,12 @@
- type: loadout
id: LoadoutServiceClownBootsWinter
- category: JobsAUncategorized
- cost: 1
+ category: JobsServiceUncategorized
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutShoesService
- !type:CharacterJobRequirement
jobs:
- Clown
@@ -65,10 +75,12 @@
- type: loadout
id: LoadoutServiceClownMaskSexy
- category: JobsAUncategorized
- cost: 1
+ category: JobsServiceUncategorized
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutMaskService
- !type:CharacterJobRequirement
jobs:
- Clown
@@ -77,21 +89,28 @@
- type: loadout
id: LoadoutServiceClownBedsheetClown
- category: JobsAUncategorized
- cost: 2
+ category: JobsServiceUncategorized
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutNeckService
- !type:CharacterJobRequirement
jobs:
- Clown
items:
- BedsheetClown
+# For the most part we dont want people to take this item, so its used as an example of all the things
+# you can do with requirements. Point someone to this thing if they ask "how tf do loadout requirements work?"
+
- type: loadout
id: LoadoutServiceClownCowToolboxFilled
- category: JobsAUncategorized
- cost: 3
+ category: JobsServiceUncategorized
+ cost: 2
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutEquipmentService
- !type:CharacterLogicXorRequirement
requirements:
- !type:CharacterLogicAndRequirement
@@ -121,7 +140,7 @@
- !type:CharacterSexRequirement
sex: Male
- !type:CharacterJobRequirement
- inverted: true
+ inverted: true # This is the equivalent of !(condition)
jobs:
- Clown
- !type:CharacterJobRequirement
@@ -133,10 +152,12 @@
# Mime
- type: loadout
id: LoadoutServiceMimeOuterWinter
- category: JobsAUncategorized
- cost: 2
+ category: JobsServiceUncategorized
+ cost: 1
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutOuterService
- !type:CharacterJobRequirement
jobs:
- Mime
@@ -145,10 +166,12 @@
- type: loadout
id: LoadoutServiceMimeMaskSad
- category: JobsAUncategorized
- cost: 1
+ category: JobsServiceUncategorized
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutMaskService
- !type:CharacterJobRequirement
jobs:
- Mime
@@ -157,10 +180,12 @@
- type: loadout
id: LoadoutServiceMimeMaskScared
- category: JobsAUncategorized
- cost: 1
+ category: JobsServiceUncategorized
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutMaskService
- !type:CharacterJobRequirement
jobs:
- Mime
@@ -169,10 +194,12 @@
- type: loadout
id: LoadoutServiceMimeMaskSexy
- category: JobsAUncategorized
- cost: 1
+ category: JobsServiceUncategorized
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutMaskService
- !type:CharacterJobRequirement
jobs:
- Mime
@@ -181,10 +208,12 @@
- type: loadout
id: LoadoutServiceMimeShoesBootsWinter
- category: JobsAUncategorized
- cost: 1
+ category: JobsServiceUncategorized
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutShoesService
- !type:CharacterJobRequirement
jobs:
- Mime
@@ -193,10 +222,12 @@
- type: loadout
id: LoadoutServiceMimeBedsheetMime
- category: JobsAUncategorized
- cost: 2
+ category: JobsServiceUncategorized
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutNeckService
- !type:CharacterJobRequirement
jobs:
- Mime
@@ -206,23 +237,97 @@
# Bartender
- type: loadout
id: LoadoutServiceBartenderUniformPurple
- category: JobsAUncategorized
- cost: 2
+ category: JobsServiceBartender
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsService
- !type:CharacterJobRequirement
jobs:
- Bartender
items:
- ClothingUniformJumpsuitBartenderPurple
+- type: loadout
+ id: LoadoutServiceBartenderArmorDuraVest
+ category: JobsServiceBartender
+ cost: 0
+ exclusive: true
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutBartenderOuterwear
+ - !type:CharacterJobRequirement
+ jobs:
+ - Bartender
+ items:
+ - ClothingOuterArmorDuraVest
+
+- type: loadout
+ id: LoadoutServiceBartenderBoxBeanbags
+ category: JobsServiceBartender
+ cost: 0
+ exclusive: true
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutBartenderAmmo
+ - !type:CharacterJobRequirement
+ jobs:
+ - Bartender
+ items:
+ - BoxBeanbag
+
+- type: loadout
+ id: LoadoutServiceBartenderBoxLightRifleRubber
+ category: JobsServiceBartender
+ cost: 1
+ exclusive: true
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutBartenderAmmo
+ - !type:CharacterJobRequirement
+ jobs:
+ - Bartender
+ items:
+ - MagazineBoxLightRifleRubber
+
+- type: loadout
+ id: LoadoutServiceBartenderShotgunDoubleBarreledRubber
+ category: JobsServiceBartender
+ cost: 0
+ exclusive: true
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutBartenderWeapon
+ - !type:CharacterJobRequirement
+ jobs:
+ - Bartender
+ items:
+ - WeaponShotgunDoubleBarreledRubber
+
+- type: loadout
+ id: LoadoutServiceBartenderMosinRubber
+ category: JobsServiceBartender
+ cost: 3
+ exclusive: true
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutBartenderWeapon
+ - !type:CharacterJobRequirement
+ jobs:
+ - Bartender
+ items:
+ - WeaponSniperMosinRubber
+
# Botanist
- type: loadout
id: LoadoutServiceBotanistUniformOveralls
- category: JobsAUncategorized
- cost: 2
+ category: JobsServiceUncategorized
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsService
- !type:CharacterJobRequirement
jobs:
- Botanist
@@ -232,10 +337,12 @@
# Lawyer
- type: loadout
id: LoadoutServiceLawyerUniformBlueSuit
- category: JobsAUncategorized
- cost: 2
+ category: JobsServiceUncategorized
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsService
- !type:CharacterJobRequirement
jobs:
- Lawyer
@@ -244,10 +351,12 @@
- type: loadout
id: LoadoutServiceLawyerUniformBlueSkirt
- category: JobsAUncategorized
- cost: 2
+ category: JobsServiceUncategorized
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsService
- !type:CharacterJobRequirement
jobs:
- Lawyer
@@ -256,10 +365,12 @@
- type: loadout
id: LoadoutServiceLawyerUniformRedSuit
- category: JobsAUncategorized
- cost: 2
+ category: JobsServiceUncategorized
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsService
- !type:CharacterJobRequirement
jobs:
- Lawyer
@@ -268,10 +379,12 @@
- type: loadout
id: LoadoutServiceLawyerUniformRedSkirt
- category: JobsAUncategorized
- cost: 2
+ category: JobsServiceUncategorized
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsService
- !type:CharacterJobRequirement
jobs:
- Lawyer
@@ -280,10 +393,12 @@
- type: loadout
id: LoadoutServiceLawyerUniformPurpleSuit
- category: JobsAUncategorized
- cost: 2
+ category: JobsServiceUncategorized
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsService
- !type:CharacterJobRequirement
jobs:
- Lawyer
@@ -292,10 +407,12 @@
- type: loadout
id: LoadoutServiceLawyerUniformPurpleSkirt
- category: JobsAUncategorized
- cost: 2
+ category: JobsServiceUncategorized
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsService
- !type:CharacterJobRequirement
jobs:
- Lawyer
@@ -304,10 +421,12 @@
- type: loadout
id: LoadoutServiceLawyerUniformGoodSuit
- category: JobsAUncategorized
- cost: 2
+ category: JobsServiceUncategorized
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsService
- !type:CharacterJobRequirement
jobs:
- Lawyer
@@ -316,10 +435,12 @@
- type: loadout
id: LoadoutServiceLawyerUniformGoodSkirt
- category: JobsAUncategorized
- cost: 2
+ category: JobsServiceUncategorized
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsService
- !type:CharacterJobRequirement
jobs:
- Lawyer
@@ -328,10 +449,12 @@
- type: loadout
id: LoadoutServiceReporterUniformJournalist
- category: JobsAUncategorized
- cost: 2
+ category: JobsServiceUncategorized
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsService
- !type:CharacterJobRequirement
jobs:
- Reporter
@@ -341,10 +464,12 @@
# Reporter
- type: loadout
id: LoadoutServiceReporterUniformDetectivesuit
- category: JobsAUncategorized
- cost: 2
+ category: JobsServiceUncategorized
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsService
- !type:CharacterJobRequirement
jobs:
- Reporter
@@ -353,10 +478,12 @@
- type: loadout
id: LoadoutServiceReporterUniformDetectiveskirt
- category: JobsAUncategorized
- cost: 2
+ category: JobsServiceUncategorized
+ cost: 0
exclusive: true
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutUniformsService
- !type:CharacterJobRequirement
jobs:
- Reporter
@@ -365,12 +492,170 @@
# Musician
- type: loadout
- id: LoadoutItemSynthesizerInstrument
- category: JobsAUncategorized
- cost: 8
+ id: LoadoutItemSynthesizerInstrumentMusician
+ category: JobsServiceUncategorized
+ cost: 2
requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutMusicianInstruments
- !type:CharacterJobRequirement
jobs:
- Musician
items:
- SynthesizerInstrument
+
+- type: loadout
+ id: LoadoutItemMicrophoneInstrumentMusician
+ category: JobsServiceUncategorized
+ cost: 0
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutMusicianInstruments
+ - !type:CharacterJobRequirement
+ jobs:
+ - Musician
+ items:
+ - MicrophoneInstrument
+
+- type: loadout
+ id: LoadoutItemKalimbaInstrumentMusician
+ category: Items
+ cost: 0
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutMusicianInstruments
+ - !type:CharacterJobRequirement
+ jobs:
+ - Musician
+ items:
+ - KalimbaInstrument
+
+- type: loadout
+ id: LoadoutItemTrumpetInstrumentMusician
+ category: Items
+ cost: 2
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutMusicianInstruments
+ - !type:CharacterJobRequirement
+ jobs:
+ - Musician
+ items:
+ - TrumpetInstrument
+
+- type: loadout
+ id: LoadoutItemElectricGuitarInstrumentMusician
+ category: Items
+ cost: 2
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutMusicianInstruments
+ - !type:CharacterJobRequirement
+ jobs:
+ - Musician
+ items:
+ - ElectricGuitarInstrument
+
+- type: loadout
+ id: LoadoutItemBassGuitarInstrumentMusician
+ category: Items
+ cost: 2
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutMusicianInstruments
+ - !type:CharacterJobRequirement
+ jobs:
+ - Musician
+ items:
+ - BassGuitarInstrument
+
+- type: loadout
+ id: LoadoutItemRockGuitarInstrumentMusician
+ category: Items
+ cost: 2
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutMusicianInstruments
+ - !type:CharacterJobRequirement
+ jobs:
+ - Musician
+ items:
+ - RockGuitarInstrument
+
+- type: loadout
+ id: LoadoutItemAcousticGuitarInstrumentMusician
+ category: Items
+ cost: 2
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutMusicianInstruments
+ - !type:CharacterJobRequirement
+ jobs:
+ - Musician
+ items:
+ - AcousticGuitarInstrument
+
+- type: loadout
+ id: LoadoutItemViolinInstrumentMusician
+ category: Items
+ cost: 2
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutMusicianInstruments
+ - !type:CharacterJobRequirement
+ jobs:
+ - Musician
+ items:
+ - ViolinInstrument
+
+- type: loadout
+ id: LoadoutItemHarmonicaInstrumentMusician
+ category: Items
+ cost: 0
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutMusicianInstruments
+ - !type:CharacterJobRequirement
+ jobs:
+ - Musician
+ items:
+ - HarmonicaInstrument
+
+- type: loadout
+ id: LoadoutItemAccordionInstrumentMusician
+ category: Items
+ cost: 0
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutMusicianInstruments
+ - !type:CharacterJobRequirement
+ jobs:
+ - Musician
+ items:
+ - AccordionInstrument
+
+- type: loadout
+ id: LoadoutItemFluteInstrumentMusician
+ category: Items
+ cost: 0
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutMusicianInstruments
+ - !type:CharacterJobRequirement
+ jobs:
+ - Musician
+ items:
+ - FluteInstrument
+
+- type: loadout
+ id: LoadoutItemOcarinaInstrumentMusician
+ category: Items
+ cost: 0
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: LoadoutMusicianInstruments
+ - !type:CharacterJobRequirement
+ jobs:
+ - Musician
+ items:
+ - OcarinaInstrument
\ No newline at end of file
diff --git a/Resources/Prototypes/Loadouts/items.yml b/Resources/Prototypes/Loadouts/items.yml
index 97a3ed2fdc..12fc1cdf85 100644
--- a/Resources/Prototypes/Loadouts/items.yml
+++ b/Resources/Prototypes/Loadouts/items.yml
@@ -139,6 +139,10 @@
requirements:
- !type:CharacterItemGroupRequirement
group: LoadoutInstrumentsAny
+ - !type:CharacterJobRequirement
+ inverted: true
+ jobs:
+ - Musician
- type: loadout
id: LoadoutItemKalimbaInstrument
@@ -149,6 +153,10 @@
requirements:
- !type:CharacterItemGroupRequirement
group: LoadoutInstrumentsAny
+ - !type:CharacterJobRequirement
+ inverted: true
+ jobs:
+ - Musician
- type: loadout
id: LoadoutItemTrumpetInstrument
@@ -159,6 +167,10 @@
requirements:
- !type:CharacterItemGroupRequirement
group: LoadoutInstrumentsAny
+ - !type:CharacterJobRequirement
+ inverted: true
+ jobs:
+ - Musician
- type: loadout
id: LoadoutItemElectricGuitar
@@ -169,6 +181,10 @@
requirements:
- !type:CharacterItemGroupRequirement
group: LoadoutInstrumentsAny
+ - !type:CharacterJobRequirement
+ inverted: true
+ jobs:
+ - Musician
- type: loadout
id: LoadoutItemBassGuitar
@@ -179,6 +195,10 @@
requirements:
- !type:CharacterItemGroupRequirement
group: LoadoutInstrumentsAny
+ - !type:CharacterJobRequirement
+ inverted: true
+ jobs:
+ - Musician
- type: loadout
id: LoadoutItemRockGuitar
@@ -189,6 +209,10 @@
requirements:
- !type:CharacterItemGroupRequirement
group: LoadoutInstrumentsAny
+ - !type:CharacterJobRequirement
+ inverted: true
+ jobs:
+ - Musician
- type: loadout
id: LoadoutItemAcousticGuitar
@@ -199,6 +223,10 @@
requirements:
- !type:CharacterItemGroupRequirement
group: LoadoutInstrumentsAny
+ - !type:CharacterJobRequirement
+ inverted: true
+ jobs:
+ - Musician
- type: loadout
id: LoadoutItemViolin
@@ -209,6 +237,10 @@
requirements:
- !type:CharacterItemGroupRequirement
group: LoadoutInstrumentsAny
+ - !type:CharacterJobRequirement
+ inverted: true
+ jobs:
+ - Musician
- type: loadout
id: LoadoutItemHarmonica
@@ -219,6 +251,10 @@
requirements:
- !type:CharacterItemGroupRequirement
group: LoadoutInstrumentsAny
+ - !type:CharacterJobRequirement
+ inverted: true
+ jobs:
+ - Musician
- type: loadout
id: LoadoutItemAccordion
@@ -229,6 +265,10 @@
requirements:
- !type:CharacterItemGroupRequirement
group: LoadoutInstrumentsAny
+ - !type:CharacterJobRequirement
+ inverted: true
+ jobs:
+ - Musician
- type: loadout
id: LoadoutItemFlute
@@ -239,6 +279,10 @@
requirements:
- !type:CharacterItemGroupRequirement
group: LoadoutInstrumentsAny
+ - !type:CharacterJobRequirement
+ inverted: true
+ jobs:
+ - Musician
- type: loadout
id: LoadoutItemOcarina
@@ -249,6 +293,10 @@
requirements:
- !type:CharacterItemGroupRequirement
group: LoadoutInstrumentsAny
+ - !type:CharacterJobRequirement
+ inverted: true
+ jobs:
+ - Musician
# Survival Kit
- type: loadout
diff --git a/Resources/Prototypes/Mood/drugs.yml b/Resources/Prototypes/Mood/drugs.yml
new file mode 100644
index 0000000000..470abc5e3d
--- /dev/null
+++ b/Resources/Prototypes/Mood/drugs.yml
@@ -0,0 +1,34 @@
+# Drugs should be paired up in Trios of "Bonus, Penalty, Category"
+
+# Lotophagoi Oil
+- type: moodEffect
+ id: LotoTranscendence
+ moodChange: 30
+ timeout: 900 #15 minutes
+ moodletOnEnd: LotoEnthrallment
+ category: "LotophagoiAddiction"
+
+- type: moodEffect
+ id: LotoEnthrallment
+ moodChange: -30
+ timeout: 7200 #2 hours
+ category: "LotophagoiAddiction"
+
+- type: moodCategory
+ id: LotophagoiAddiction
+
+# Nicotine
+- type: moodEffect
+ id: NicotineBenefit
+ moodChange: 5
+ timeout: 600 #10 minutes
+ moodletOnEnd: NicotineWithdrawal
+ category: "NicotineAddiction"
+
+- type: moodEffect
+ id: NicotineWithdrawal
+ moodChange: -7 #No timeout
+ category: "NicotineAddiction"
+
+- type: moodCategory
+ id: NicotineAddiction
\ No newline at end of file
diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Objects/Devices/CircuitBoards/production.yml b/Resources/Prototypes/Nyanotrasen/Entities/Objects/Devices/CircuitBoards/production.yml
index 6e80ec7c4e..2ed4a594e3 100644
--- a/Resources/Prototypes/Nyanotrasen/Entities/Objects/Devices/CircuitBoards/production.yml
+++ b/Resources/Prototypes/Nyanotrasen/Entities/Objects/Devices/CircuitBoards/production.yml
@@ -12,9 +12,8 @@
MatterBin: 1
Manipulator: 1
materialRequirements:
- Glass: 1
Cable: 1
- Diamond: 10
+ PlasmaGlass: 5
tagRequirements:
BorgArm:
Amount: 3
diff --git a/Resources/Prototypes/Nyanotrasen/GameRules/events.yml b/Resources/Prototypes/Nyanotrasen/GameRules/events.yml
index 43347ca7d0..524bf4d4b7 100644
--- a/Resources/Prototypes/Nyanotrasen/GameRules/events.yml
+++ b/Resources/Prototypes/Nyanotrasen/GameRules/events.yml
@@ -24,13 +24,13 @@
earliestStart: 25
- type: MidRoundAntagRule
-#- type: entity
-# noSpawn: true
-# parent: BaseMidRoundAntag
-# id: RatKingSpawn
-# components:
-# - type: MidRoundAntagRule
-# spawner: SpawnPointGhostRatKing
+- type: entity
+ noSpawn: true
+ parent: BaseMidRoundAntag
+ id: RatKingSpawn
+ components:
+ - type: MidRoundAntagRule
+ spawner: SpawnPointGhostRatKing
- type: entity
noSpawn: true
diff --git a/Resources/Prototypes/Nyanotrasen/Reagents/Consumable/Drink/alcohol.yml b/Resources/Prototypes/Nyanotrasen/Reagents/Consumable/Drink/alcohol.yml
index 972fc08239..19d49b913a 100644
--- a/Resources/Prototypes/Nyanotrasen/Reagents/Consumable/Drink/alcohol.yml
+++ b/Resources/Prototypes/Nyanotrasen/Reagents/Consumable/Drink/alcohol.yml
@@ -19,7 +19,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.07
+ amount: 0.15
- type: reagent
id: Soju
@@ -42,7 +42,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.15
+ amount: 0.2
- type: reagent
id: OrangeCreamice
@@ -65,7 +65,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.05
+ amount: 0.1
- type: reagent
id: Silverjack
@@ -88,7 +88,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.0625
+ amount: 0.1375
- type: reagent
id: Brainbomb
@@ -118,7 +118,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.085
+ amount: 0.13
- !type:AdjustReagent
reagent: THC
amount: 0.33
@@ -147,7 +147,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.025
+ amount: 0.08
- type: reagent
id: CircusJuice
@@ -170,7 +170,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.0625
+ amount: 0.12
- !type:Emote #It's very funny
emote: Laugh
probability: 0.15
@@ -196,7 +196,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.065
+ amount: 0.1125
- !type:AdjustTemperature
amount: 75 # thermal energy, not temperature!
@@ -221,4 +221,4 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.03
+ amount: 0.12
diff --git a/Resources/Prototypes/Nyanotrasen/Recipes/Lathes/electronics.yml b/Resources/Prototypes/Nyanotrasen/Recipes/Lathes/electronics.yml
index 1e53c715af..695fb42150 100644
--- a/Resources/Prototypes/Nyanotrasen/Recipes/Lathes/electronics.yml
+++ b/Resources/Prototypes/Nyanotrasen/Recipes/Lathes/electronics.yml
@@ -4,7 +4,7 @@
completetime: 4
materials:
Steel: 100
- Glass: 900
+ Glass: 700
Gold: 100
- type: latheRecipe
@@ -13,7 +13,7 @@
completetime: 4
materials:
Steel: 100
- Glass: 900
+ Glass: 700
Gold: 100
- type: latheRecipe
@@ -21,8 +21,8 @@
result: CrewMonitoringComputerCircuitboard
completetime: 4
materials:
- Steel: 100
- Glass: 900
+ Steel: 100
+ Glass: 700
- type: latheRecipe
id: ClothingEyesHudMedical
@@ -41,4 +41,4 @@
completetime: 4
materials:
Steel: 100
- Glass: 900
+ Glass: 700
diff --git a/Resources/Prototypes/Reagents/Consumable/Drink/alcohol.yml b/Resources/Prototypes/Reagents/Consumable/Drink/alcohol.yml
index e31087c309..d9e57d5b80 100644
--- a/Resources/Prototypes/Reagents/Consumable/Drink/alcohol.yml
+++ b/Resources/Prototypes/Reagents/Consumable/Drink/alcohol.yml
@@ -22,7 +22,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.3
+ amount: 0.7
- type: reagent
id: Ale
@@ -77,7 +77,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.1
+ amount: 0.25
- type: reagent
id: BlueHawaiian
@@ -97,7 +97,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.2
+ amount: 0.154
- type: reagent
id: Cognac
@@ -121,7 +121,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.2
+ amount: 0.4
- type: reagent
id: DeadRum
@@ -144,7 +144,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.2
+ amount: 0.6
- type: reagent
id: Ethanol
@@ -163,7 +163,7 @@
- !type:HealthChange
conditions:
- !type:ReagentThreshold
- min: 15
+ min: 45
damage:
types:
Poison: 1
@@ -278,7 +278,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.2
+ amount: 0.45
- type: reagent
id: CoffeeLiqueur
@@ -294,6 +294,13 @@
metamorphicMaxFillLevels: 3
metamorphicFillBaseName: fill-
metamorphicChangeColor: true
+ metabolisms:
+ Drink:
+ effects:
+ - !type:AdjustReagent
+ reagent: Ethanol
+ amount: 0.20
+
- type: reagent
id: MelonLiquor
@@ -309,6 +316,12 @@
metamorphicMaxFillLevels: 5
metamorphicFillBaseName: fill-
metamorphicChangeColor: true
+ metabolisms:
+ Drink:
+ effects:
+ - !type:AdjustReagent
+ reagent: Ethanol
+ amount: 0.20
- type: reagent
id: NTCahors
@@ -324,6 +337,12 @@
metamorphicMaxFillLevels: 5
metamorphicFillBaseName: fill-
metamorphicChangeColor: true
+ metabolisms:
+ Drink:
+ effects:
+ - !type:AdjustReagent
+ reagent: Ethanol
+ amount: 0.17
- type: reagent
id: PoisonWine
@@ -346,7 +365,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.05
+ amount: 0.11
Poison:
effects:
- !type:HealthChange
@@ -376,7 +395,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.2
+ amount: 0.40
##Commented out in favor of Nyano sake/soju
#- type: reagent
@@ -409,7 +428,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.2
+ amount: 0.40
- type: reagent
id: Vermouth
@@ -425,6 +444,12 @@
metamorphicMaxFillLevels: 4
metamorphicFillBaseName: fill-
metamorphicChangeColor: false
+ metabolisms:
+ Drink:
+ effects:
+ - !type:AdjustReagent
+ reagent: Ethanol
+ amount: 0.16
- type: reagent
id: Vodka
@@ -448,7 +473,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.2
+ amount: 0.40
- type: reagent
id: Whiskey
@@ -472,7 +497,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.2
+ amount: 0.40
- type: reagent
id: Wine
@@ -489,6 +514,14 @@
metamorphicMaxFillLevels: 5
metamorphicFillBaseName: fill-
metamorphicChangeColor: true
+ metabolisms:
+ Drink:
+ effects:
+ - !type:SatiateThirst
+ factor: 2
+ - !type:AdjustReagent
+ reagent: Ethanol
+ amount: 0.11
- type: reagent
id: Champagne
@@ -512,7 +545,7 @@
factor: 3
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.3
+ amount: 0.12
# Mixed Alcohol
@@ -530,6 +563,14 @@
metamorphicMaxFillLevels: 5
metamorphicFillBaseName: fill-
metamorphicChangeColor: false
+ metabolisms:
+ Drink:
+ effects:
+ - !type:SatiateThirst
+ factor: 1
+ - !type:AdjustReagent
+ reagent: Ethanol
+ amount: 0.073
- type: reagent
id: AlliesCocktail
@@ -545,6 +586,14 @@
metamorphicMaxFillLevels: 4
metamorphicFillBaseName: fill-
metamorphicChangeColor: false
+ metabolisms:
+ Drink:
+ effects:
+ - !type:SatiateThirst
+ factor: 2
+ - !type:AdjustReagent
+ reagent: Ethanol
+ amount: 0.37
- type: reagent
id: Aloe
@@ -575,6 +624,14 @@
metamorphicMaxFillLevels: 5
metamorphicFillBaseName: fill-
metamorphicChangeColor: false
+ metabolisms:
+ Drink:
+ effects:
+ - !type:SatiateThirst
+ factor: 2
+ - !type:AdjustReagent
+ reagent: Ethanol
+ amount: 0.204
- type: reagent
id: Andalusia
@@ -590,6 +647,14 @@
metamorphicMaxFillLevels: 4
metamorphicFillBaseName: fill-
metamorphicChangeColor: false
+ metabolisms:
+ Drink:
+ effects:
+ - !type:SatiateThirst
+ factor: 2
+ - !type:AdjustReagent
+ reagent: Ethanol
+ amount: 0.27
- type: reagent
id: Antifreeze
@@ -612,7 +677,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.15
+ amount: 0.2
- type: reagent
id: AtomicBomb
@@ -635,7 +700,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.15
+ amount: 0.254
- !type:AdjustReagent
reagent: Uranium
amount: 0.05
@@ -661,7 +726,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.15
+ amount: 0.28
- type: reagent
id: BahamaMama
@@ -677,6 +742,14 @@
metamorphicMaxFillLevels: 5
metamorphicFillBaseName: fill-
metamorphicChangeColor: true
+ metabolisms:
+ Drink:
+ effects:
+ - !type:SatiateThirst
+ factor: 2
+ - !type:AdjustReagent
+ reagent: Ethanol
+ amount: 0.11
- type: reagent
id: BananaHonk
@@ -707,6 +780,14 @@
metamorphicMaxFillLevels: 3
metamorphicFillBaseName: fill-
metamorphicChangeColor: true
+ metabolisms:
+ Drink:
+ effects:
+ - !type:SatiateThirst
+ factor: 2
+ - !type:AdjustReagent
+ reagent: Ethanol
+ amount: 0.05
- type: reagent
id: BeepskySmash
@@ -729,7 +810,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.15
+ amount: 0.13
- type: reagent
id: BlackRussian
@@ -752,7 +833,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.2
+ amount: 0.33
- type: reagent
id: BloodyMary
@@ -768,6 +849,14 @@
metamorphicMaxFillLevels: 5
metamorphicFillBaseName: fill-
metamorphicChangeColor: true
+ metabolisms:
+ Drink:
+ effects:
+ - !type:SatiateThirst
+ factor: 2
+ - !type:AdjustReagent
+ reagent: Ethanol
+ amount: 0.13
- type: reagent
id: Booger
@@ -783,6 +872,14 @@
metamorphicMaxFillLevels: 5
metamorphicFillBaseName: fill-
metamorphicChangeColor: true
+ metabolisms:
+ Drink:
+ effects:
+ - !type:SatiateThirst
+ factor: 2
+ - !type:AdjustReagent
+ reagent: Ethanol
+ amount: 0.08
- type: reagent
id: BraveBull
@@ -805,7 +902,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.2
+ amount: 0.33
- type: reagent
id: CoconutRum
@@ -825,7 +922,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.2
+ amount: 0.26
- type: reagent
id: Cosmopolitan
@@ -845,7 +942,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.15
+ amount: 0.13
- type: reagent
id: CubaLibre
@@ -868,7 +965,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.07
+ amount: 0.13
- type: reagent
id: DemonsBlood
@@ -884,6 +981,14 @@
metamorphicMaxFillLevels: 4
metamorphicFillBaseName: fill-
metamorphicChangeColor: true
+ metabolisms:
+ Drink:
+ effects:
+ - !type:SatiateThirst
+ factor: 2
+ - !type:AdjustReagent
+ reagent: Ethanol
+ amount: 0.10
- type: reagent
id: DevilsKiss
@@ -899,6 +1004,14 @@
metamorphicMaxFillLevels: 3
metamorphicFillBaseName: fill-
metamorphicChangeColor: true
+ metabolisms:
+ Drink:
+ effects:
+ - !type:SatiateThirst
+ factor: 2
+ - !type:AdjustReagent
+ reagent: Ethanol
+ amount: 0.20
- type: reagent
id: DoctorsDelight
@@ -921,9 +1034,6 @@
factor: 2
- !type:SatiateHunger
factor: -2
- - !type:AdjustReagent
- reagent: Ethanol
- amount: 0.05
Medicine:
effects:
- !type:HealthChange
@@ -955,7 +1065,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.15
+ amount: 0.225
- type: reagent
id: ErikaSurprise
@@ -971,6 +1081,14 @@
metamorphicMaxFillLevels: 5
metamorphicFillBaseName: fill-
metamorphicChangeColor: true
+ metabolisms:
+ Drink:
+ effects:
+ - !type:SatiateThirst
+ factor: 2
+ - !type:AdjustReagent
+ reagent: Ethanol
+ amount: 0.02
- type: reagent
id: GargleBlaster
@@ -993,7 +1111,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.2
+ amount: 0.32
- type: reagent
id: GinFizz
@@ -1016,7 +1134,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.07
+ amount: 0.15
- type: reagent
id: GinTonic
@@ -1039,7 +1157,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.07
+ amount: 0.15
- type: reagent
id: Gildlager
@@ -1062,7 +1180,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.2
+ amount: 0.363
- type: reagent
id: Grog
@@ -1078,6 +1196,14 @@
metamorphicMaxFillLevels: 5
metamorphicFillBaseName: fill-
metamorphicChangeColor: true
+ metabolisms:
+ Drink:
+ effects:
+ - !type:SatiateThirst
+ factor: 2
+ - !type:AdjustReagent
+ reagent: Ethanol
+ amount: 0.10
- type: reagent
id: HippiesDelight
@@ -1093,6 +1219,14 @@
metamorphicMaxFillLevels: 6
metamorphicFillBaseName: fill-
metamorphicChangeColor: false
+ metabolisms:
+ Drink:
+ effects:
+ - !type:SatiateThirst
+ factor: 2
+ - !type:AdjustReagent
+ reagent: Ethanol
+ amount: 0.16
- type: reagent
id: Hooch
@@ -1102,6 +1236,14 @@
physicalDesc: reagent-physical-desc-strong-smelling
flavor: alcohol
color: "#664e00"
+ metabolisms:
+ Drink:
+ effects:
+ - !type:SatiateThirst
+ factor: 2
+ - !type:AdjustReagent
+ reagent: Ethanol
+ amount: 0.50
- type: reagent
id: IcedBeer
@@ -1139,7 +1281,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.15
+ amount: 0.16
- type: reagent
id: IrishCream
@@ -1162,7 +1304,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.2
+ amount: 0.266
- type: reagent
id: IrishCoffee
@@ -1185,7 +1327,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.15
+ amount: 0.133
- type: reagent
id: LongIslandIcedTea
@@ -1208,7 +1350,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.15
+ amount: 0.273
- type: reagent
id: Manhattan
@@ -1224,6 +1366,14 @@
metamorphicMaxFillLevels: 3
metamorphicFillBaseName: fill-
metamorphicChangeColor: false
+ metabolisms:
+ Drink:
+ effects:
+ - !type:SatiateThirst
+ factor: 2
+ - !type:AdjustReagent
+ reagent: Ethanol
+ amount: 0.32
- type: reagent
id: ManhattanProject
@@ -1239,6 +1389,14 @@
metamorphicMaxFillLevels: 3
metamorphicFillBaseName: fill-
metamorphicChangeColor: false
+ metabolisms:
+ Drink:
+ effects:
+ - !type:SatiateThirst
+ factor: 2
+ - !type:AdjustReagent
+ reagent: Ethanol
+ amount: 0.363
- type: reagent
id: ManlyDorf
@@ -1291,7 +1449,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.15
+ amount: 0.353
- type: reagent
id: Mead
@@ -1322,6 +1480,14 @@
metamorphicMaxFillLevels: 6
metamorphicFillBaseName: fill-
metamorphicChangeColor: false
+ metabolisms:
+ Drink:
+ effects:
+ - !type:SatiateThirst
+ factor: 2
+ - !type:AdjustReagent
+ reagent: Ethanol
+ amount: 0.10
- type: reagent
id: Moonshine
@@ -1338,7 +1504,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.25
+ amount: 0.40
- type: reagent
id: Neurotoxin
@@ -1361,7 +1527,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.25
+ amount: 0.16
Poison:
effects:
- !type:HealthChange
@@ -1387,7 +1553,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.2
+ amount: 0.04
- type: reagent
id: Patron
@@ -1410,7 +1576,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.2
+ amount: 0.50
- type: reagent
id: RedMead
@@ -1438,6 +1604,14 @@
metamorphicSprite:
sprite: Objects/Consumable/Drinks/pinacolada.rsi
state: icon
+ metabolisms:
+ Drink:
+ effects:
+ - !type:SatiateThirst
+ factor: 2
+ - !type:AdjustReagent
+ reagent: Ethanol
+ amount: 0.06
- type: reagent
id: Sbiten
@@ -1453,6 +1627,14 @@
metamorphicMaxFillLevels: 5
metamorphicFillBaseName: fill-
metamorphicChangeColor: true
+ metabolisms:
+ Drink:
+ effects:
+ - !type:SatiateThirst
+ factor: 2
+ - !type:AdjustReagent
+ reagent: Ethanol
+ amount: 0.2
- type: reagent
id: ScrewdriverCocktail
@@ -1475,7 +1657,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.07
+ amount: 0.13
- type: reagent
id: CogChamp
@@ -1501,7 +1683,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.15
+ amount: 0.176
- type: reagent
id: Silencer
@@ -1540,6 +1722,14 @@
metamorphicMaxFillLevels: 5
metamorphicFillBaseName: fill-
metamorphicChangeColor: false
+ metabolisms:
+ Drink:
+ effects:
+ - !type:SatiateThirst
+ factor: 2
+ - !type:AdjustReagent
+ reagent: Ethanol
+ amount: 0.23
- type: reagent
id: SnowWhite
@@ -1555,6 +1745,14 @@
metamorphicMaxFillLevels: 6
metamorphicFillBaseName: fill-
metamorphicChangeColor: true
+ metabolisms:
+ Drink:
+ effects:
+ - !type:SatiateThirst
+ factor: 2
+ - !type:AdjustReagent
+ reagent: Ethanol
+ amount: 0.03
- type: reagent
id: SuiDream
@@ -1570,6 +1768,14 @@
metamorphicMaxFillLevels: 5
metamorphicFillBaseName: fill-
metamorphicChangeColor: false
+ metabolisms:
+ Drink:
+ effects:
+ - !type:SatiateThirst
+ factor: 2
+ - !type:AdjustReagent
+ reagent: Ethanol
+ amount: 0.13
- type: reagent
id: SyndicateBomb
@@ -1585,6 +1791,14 @@
metamorphicMaxFillLevels: 6
metamorphicFillBaseName: fill-
metamorphicChangeColor: true
+ metabolisms:
+ Drink:
+ effects:
+ - !type:SatiateThirst
+ factor: 2
+ - !type:AdjustReagent
+ reagent: Ethanol
+ amount: 0.095
- type: reagent
id: TequilaSunrise
@@ -1607,7 +1821,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.15
+ amount: 0.26
- type: reagent
id: TheMartinez
@@ -1623,6 +1837,14 @@
metamorphicMaxFillLevels: 3
metamorphicFillBaseName: fill-
metamorphicChangeColor: false
+ metabolisms:
+ Drink:
+ effects:
+ - !type:SatiateThirst
+ factor: 2
+ - !type:AdjustReagent
+ reagent: Ethanol
+ amount: 0.13
- type: reagent
id: ThreeMileIsland
@@ -1645,7 +1867,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.15
+ amount: 0.273
- !type:AdjustReagent
reagent: Uranium
amount: 0.05
@@ -1664,6 +1886,14 @@
metamorphicMaxFillLevels: 4
metamorphicFillBaseName: fill-
metamorphicChangeColor: false
+ metabolisms:
+ Drink:
+ effects:
+ - !type:SatiateThirst
+ factor: 2
+ - !type:AdjustReagent
+ reagent: Ethanol
+ amount: 0.112
- type: reagent
id: VodkaMartini
@@ -1686,7 +1916,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.15
+ amount: 0.32
- type: reagent
id: VodkaTonic
@@ -1709,7 +1939,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.07
+ amount: 0.13
- type: reagent
id: WhiskeyCola
@@ -1732,7 +1962,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.07
+ amount: 0.013
- type: reagent
id: WhiskeySoda
@@ -1755,7 +1985,7 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.07
+ amount: 0.13
- type: reagent
id: WhiteGilgamesh
@@ -1772,7 +2002,7 @@
factor: 1
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.15
+ amount: 0.04
- type: reagent
id: WhiteRussian
@@ -1795,4 +2025,4 @@
factor: 2
- !type:AdjustReagent
reagent: Ethanol
- amount: 0.15
+ amount: 0.33
diff --git a/Resources/Prototypes/Reagents/narcotics.yml b/Resources/Prototypes/Reagents/narcotics.yml
index 2ab323c309..ca85fd15b3 100644
--- a/Resources/Prototypes/Reagents/narcotics.yml
+++ b/Resources/Prototypes/Reagents/narcotics.yml
@@ -212,6 +212,11 @@
plantMetabolism:
- !type:PlantAdjustHealth
amount: -5
+ metabolisms:
+ Narcotic:
+ effects:
+ - !type:ChemAddMoodlet
+ moodPrototype: NicotineBenefit
# TODO: Replace these nonstandardized effects with generic brain damage
- type: reagent
@@ -260,7 +265,7 @@
type: Add
time: 5
refresh: false
- - !type:ChemRerollPsionic #Nyano - Summary: lets the imbiber become psionic.
+ - !type:ChemRerollPsionic #Nyano - Summary: lets the imbiber become psionic.
conditions:
- !type:ReagentThreshold
reagent: SpaceDrugs
diff --git a/Resources/Prototypes/Reagents/psionic.yml b/Resources/Prototypes/Reagents/psionic.yml
index 3e8415fc0e..f17a84047a 100644
--- a/Resources/Prototypes/Reagents/psionic.yml
+++ b/Resources/Prototypes/Reagents/psionic.yml
@@ -92,6 +92,12 @@
- !type:GenericStatusEffect
key: SlurredSpeech
component: TelepathicRepeater
+ - !type:ChemAddMoodlet
+ moodPrototype: LotoTranscendence
+ conditions:
+ - !type:ReagentThreshold
+ reagent: LotophagoiOil
+ min: 5
- type: reagent
id: Ectoplasm
diff --git a/Resources/Prototypes/Recipes/Reactions/drinks.yml b/Resources/Prototypes/Recipes/Reactions/drinks.yml
index c810ebb0ce..812cded972 100644
--- a/Resources/Prototypes/Recipes/Reactions/drinks.yml
+++ b/Resources/Prototypes/Recipes/Reactions/drinks.yml
@@ -857,7 +857,7 @@
LemonLime:
amount: 1
products:
- SnowWhite: 3
+ SnowWhite: 2
- type: reaction
id: SoyLatte
diff --git a/Resources/Prototypes/Research/experimental.yml b/Resources/Prototypes/Research/experimental.yml
index 0dbcded546..d46e1db144 100644
--- a/Resources/Prototypes/Research/experimental.yml
+++ b/Resources/Prototypes/Research/experimental.yml
@@ -56,6 +56,7 @@
cost: 5000
recipeUnlocks:
- TechDiskComputerCircuitboard
+ - ReverseEngineeringMachineCircuitboard #DeltaV
- type: technology
id: MagnetsTech
diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/lawyer.yml b/Resources/Prototypes/Roles/Jobs/Civilian/lawyer.yml
index b7e3cc2223..c05d861280 100644
--- a/Resources/Prototypes/Roles/Jobs/Civilian/lawyer.yml
+++ b/Resources/Prototypes/Roles/Jobs/Civilian/lawyer.yml
@@ -20,7 +20,7 @@
shoes: ClothingShoesBootsLaceup
id: LawyerPDA
ears: ClothingHeadsetSecurity
- # TODO add copy of space law
+ pocket1: BookSecurity
inhand:
- BriefcaseBrownFilled
innerClothingSkirt: ClothingUniformJumpskirtLawyerBlack
diff --git a/Resources/Prototypes/Roles/Jobs/Engineering/atmospheric_technician.yml b/Resources/Prototypes/Roles/Jobs/Engineering/atmospheric_technician.yml
index 6371978425..aeca27189c 100644
--- a/Resources/Prototypes/Roles/Jobs/Engineering/atmospheric_technician.yml
+++ b/Resources/Prototypes/Roles/Jobs/Engineering/atmospheric_technician.yml
@@ -17,12 +17,12 @@
id: AtmosphericTechnicianGear
equipment:
jumpsuit: ClothingUniformJumpsuitAtmos
- back: ClothingBackpackAtmosphericsFilled
+ back: ClothingBackpackEngineeringFilled
shoes: ClothingShoesColorWhite
eyes: ClothingEyesGlassesMeson
id: AtmosPDA
belt: ClothingBeltUtilityEngineering
ears: ClothingHeadsetEngineering
innerClothingSkirt: ClothingUniformJumpskirtAtmos
- satchel: ClothingBackpackSatchelAtmosphericsFilled
- duffelbag: ClothingBackpackDuffelAtmosphericsFilled
+ satchel: ClothingBackpackSatchelEngineeringFilled
+ duffelbag: ClothingBackpackDuffelEngineeringFilled
diff --git a/Resources/Prototypes/Shaders/shaders.yml b/Resources/Prototypes/Shaders/shaders.yml
index b495490201..3f0cb5ae1f 100644
--- a/Resources/Prototypes/Shaders/shaders.yml
+++ b/Resources/Prototypes/Shaders/shaders.yml
@@ -104,3 +104,10 @@
id: SaturationScale
kind: source
path: "/Textures/Shaders/saturationscale.swsl"
+
+ # Flight shaders
+
+- type: shader
+ id: Flap
+ kind: source
+ path: "/Textures/Shaders/flap.swsl"
\ No newline at end of file
diff --git a/Resources/Prototypes/SoundCollections/flight.yml b/Resources/Prototypes/SoundCollections/flight.yml
new file mode 100644
index 0000000000..cca2cfb014
--- /dev/null
+++ b/Resources/Prototypes/SoundCollections/flight.yml
@@ -0,0 +1,6 @@
+- type: soundCollection
+ id: WingFlaps
+ files:
+ - /Audio/Effects/Flight/wingflap1.ogg
+ - /Audio/Effects/Flight/wingflap2.ogg
+ - /Audio/Effects/Flight/wingflap3.ogg
diff --git a/Resources/Prototypes/Traits/disabilities.yml b/Resources/Prototypes/Traits/disabilities.yml
index c0b942ea66..c24e892769 100644
--- a/Resources/Prototypes/Traits/disabilities.yml
+++ b/Resources/Prototypes/Traits/disabilities.yml
@@ -65,7 +65,7 @@
- type: trait
id: Uncloneable
category: Physical
- points: 4
+ points: 1
requirements:
- !type:CharacterJobRequirement
inverted: true
@@ -168,8 +168,8 @@
species:
- IPC
components:
- - type: BloodDeficiency # 0.07 = start taking bloodloss damage at around ~21.4 minutes,
- bloodLossAmount: 0.07 # then become crit ~10 minutes later
+ - type: BloodDeficiency # by default, start taking bloodloss damage at around ~21.4 minutes,
+ bloodLossPercentage: 0.0002333333 # then become crit ~10 minutes
- type: trait
id: Hemophilia
diff --git a/Resources/Prototypes/Traits/neutral.yml b/Resources/Prototypes/Traits/neutral.yml
index b9f988106d..a103f5abee 100644
--- a/Resources/Prototypes/Traits/neutral.yml
+++ b/Resources/Prototypes/Traits/neutral.yml
@@ -54,9 +54,8 @@
inverted: true
traits:
- Sanguine
- components:
- - type: MoodModifyTrait
- moodId: TraitSaturnine
+ moodEffects:
+ - TraitSaturnine
- type: trait
id: Sanguine
@@ -72,6 +71,22 @@
inverted: true
traits:
- Saturnine
- components:
- - type: MoodModifyTrait
- moodId: TraitSanguine
\ No newline at end of file
+ moodEffects:
+ - TraitSanguine
+
+- type: trait
+ id: AddictionNicotine
+ category: Mental
+ points: 1
+ requirements:
+ - !type:CharacterJobRequirement
+ inverted: true
+ jobs:
+ - Borg
+ - MedicalBorg
+ - !type:CharacterSpeciesRequirement
+ inverted: true
+ species:
+ - IPC
+ moodEffects:
+ - NicotineWithdrawal
\ No newline at end of file
diff --git a/Resources/Prototypes/Wires/layouts.yml b/Resources/Prototypes/Wires/layouts.yml
index 8d6be674e8..cf76e0ea61 100644
--- a/Resources/Prototypes/Wires/layouts.yml
+++ b/Resources/Prototypes/Wires/layouts.yml
@@ -1,6 +1,7 @@
- type: wireLayout
id: Airlock
wires:
+ - !type:AccessWireAction
- !type:PowerWireAction
- !type:PowerWireAction
pulseTimeout: 15
@@ -44,6 +45,7 @@
- type: wireLayout
id: HighSec
wires:
+ - !type:AccessWireAction
- !type:PowerWireAction
pulseTimeout: 10
- !type:DoorBoltWireAction
diff --git a/Resources/ServerInfo/Guidebook/Service/FoodRecipes.xml b/Resources/ServerInfo/Guidebook/Service/FoodRecipes.xml
index 797591dd78..c74b947dbf 100644
--- a/Resources/ServerInfo/Guidebook/Service/FoodRecipes.xml
+++ b/Resources/ServerInfo/Guidebook/Service/FoodRecipes.xml
@@ -1,88 +1,9 @@
-## Starting Out
-This is not an extensive list of recipes, these listings are to showcase the basics.
+## Recipe list
+Note: Only solid foods are listed here! To learn recipes for liquid ingredients, check the chemistry guidebook.
-Mixes are done in a Beaker, foods are cooked in a Microwave. Cook times will be listed.
+This list is auto-generated and contains all known foods.
-WARNING: This is not an automatically generated list, things here may become outdated. The wiki has much more than is listed here.
-
-## The Basics: Mixing
-
-- Dough = 15 Flour, 10 Water
-- Cornmeal Dough = 1 Egg (6u), 10 Milk, 15 Cornmeal
-- 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
-- Vegan Cake Batter = 15 Soy Milk, 15 Flour, 5 Sugar
-- Butter = 30 Milk, 5 Table Salt (Catalyst)
-- Cheese Wheel = 5 Enzyme (Catalyst), 40 Milk
-- Chèvre Log = 5 Enzyme (Catalyst), 10 Goat Milk
-- Meatball = 1 Egg (6u), 5 Flour, 5 Uncooked Animal Proteins
-- Chocolate = 6 Cocoa Powder, 2 Milk, 2 Sugar
-- Uncooked Animal Protein: Grind Raw Meat
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-## Secondary Products
-
-- Dough Slice: Cut Dough
-- Bun: Microwave Dough Slice for 5 Seconds
-- Cutlet: Slice Raw Meat
-- Cheese Wedge: Slice Cheese Wheel
-- Flat Dough: Use a rolling pin or a round object (fire extinguisher, soda can, bottle) on Dough.
-- Tortilla Dough Slice: cut Tortilla Dough
-- Flat Tortilla Dough: Use a rolling pin or a round object (fire extinguisher, soda can, bottle) on Tortilla Dough Slice
-- Taco Shell: Microwave Flat Tortilla Dough for 5 Seconds
-
-## Food Examples
-
-- Bread: Microwave Dough for 10 Seconds
-- Plain Burger: Microwave 1 Bun and 1 Raw Meat for 10 Seconds
-- Tomato Soup: 10u Water, 1 Bowl, and 2 Tomatoes for 10 Seconds
-- Citrus Salad: 1 Bowl, 1 Lemon, 1 Lime, 1 Orange for 5 Seconds
-- Margherita Pizza: Microwave 1 Flat Dough, 1 Cheese Wedge, and 4 Tomatoes for 30 Seconds
-- Cake: 1 Cake Batter for 15 Seconds
-- Apple Pie: 1 Pie Dough, 3 Apples, and 1 Pie Tin for 15 Seconds
-- Beef Taco: Microwave 1 Taco Shell, 1 Raw Meat Cutlet, 1 Cheese Wedge for 10 Seconds
-- Cuban Carp : Microwave 1 Dough, 1 Cheese Wedge, 1 Chili, 1 Carp Meat for 15 Seconds
-- Banana Cream Pie : Microwave 1 Pie Dough, 3 Bananas, and 1 Pie Tin for 15 Seconds
-- Carrot Fries : Microwave 1 Carrot, 15u Salt for 15 Seconds
-- Pancake : Microwave 5u Flour, 5u Milk, 1 Egg (6u) for 5 Seconds
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/Resources/Textures/Interface/Actions/flight.rsi/flight_off.png b/Resources/Textures/Interface/Actions/flight.rsi/flight_off.png
new file mode 100644
index 0000000000..852dd300e9
Binary files /dev/null and b/Resources/Textures/Interface/Actions/flight.rsi/flight_off.png differ
diff --git a/Resources/Textures/Interface/Actions/flight.rsi/flight_on.png b/Resources/Textures/Interface/Actions/flight.rsi/flight_on.png
new file mode 100644
index 0000000000..c47b923a68
Binary files /dev/null and b/Resources/Textures/Interface/Actions/flight.rsi/flight_on.png differ
diff --git a/Resources/Textures/Interface/Actions/flight.rsi/meta.json b/Resources/Textures/Interface/Actions/flight.rsi/meta.json
new file mode 100644
index 0000000000..b4a013190d
--- /dev/null
+++ b/Resources/Textures/Interface/Actions/flight.rsi/meta.json
@@ -0,0 +1,17 @@
+{
+ "copyright" : "Made by dootythefrooty (273243513800622090)",
+ "license" : "CC-BY-SA-3.0",
+ "version": 1,
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "flight_off"
+ },
+ {
+ "name": "flight_on"
+ }
+ ]
+ }
\ No newline at end of file
diff --git a/Resources/Textures/Markers/environment.rsi/base-blue.png b/Resources/Textures/Markers/environment.rsi/base-blue.png
new file mode 100644
index 0000000000..ee77bb448a
Binary files /dev/null and b/Resources/Textures/Markers/environment.rsi/base-blue.png differ
diff --git a/Resources/Textures/Markers/environment.rsi/base-green.png b/Resources/Textures/Markers/environment.rsi/base-green.png
new file mode 100644
index 0000000000..a39bca9cdc
Binary files /dev/null and b/Resources/Textures/Markers/environment.rsi/base-green.png differ
diff --git a/Resources/Textures/Markers/environment.rsi/base-red.png b/Resources/Textures/Markers/environment.rsi/base-red.png
new file mode 100644
index 0000000000..e0d68f8b9e
Binary files /dev/null and b/Resources/Textures/Markers/environment.rsi/base-red.png differ
diff --git a/Resources/Textures/Markers/environment.rsi/fire.png b/Resources/Textures/Markers/environment.rsi/fire.png
new file mode 100644
index 0000000000..71abc46e81
Binary files /dev/null and b/Resources/Textures/Markers/environment.rsi/fire.png differ
diff --git a/Resources/Textures/Markers/environment.rsi/meta.json b/Resources/Textures/Markers/environment.rsi/meta.json
new file mode 100644
index 0000000000..6fc7decc8b
--- /dev/null
+++ b/Resources/Textures/Markers/environment.rsi/meta.json
@@ -0,0 +1,32 @@
+{
+ "version": 1,
+ "license": "CC-BY-NC-SA-3.0",
+ "copyright": "Nuclear14",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "base-blue"
+ },
+ {
+ "name": "base-red"
+ },
+ {
+ "name": "base-green"
+ },
+ {
+ "name": "fire"
+ },
+ {
+ "name": "rad"
+ },
+ {
+ "name": "wall"
+ },
+ {
+ "name": "weather"
+ }
+ ]
+}
diff --git a/Resources/Textures/Markers/environment.rsi/rad.png b/Resources/Textures/Markers/environment.rsi/rad.png
new file mode 100644
index 0000000000..ae01d87143
Binary files /dev/null and b/Resources/Textures/Markers/environment.rsi/rad.png differ
diff --git a/Resources/Textures/Markers/environment.rsi/wall.png b/Resources/Textures/Markers/environment.rsi/wall.png
new file mode 100644
index 0000000000..2aaeaaf014
Binary files /dev/null and b/Resources/Textures/Markers/environment.rsi/wall.png differ
diff --git a/Resources/Textures/Markers/environment.rsi/weather.png b/Resources/Textures/Markers/environment.rsi/weather.png
new file mode 100644
index 0000000000..adb9f53a47
Binary files /dev/null and b/Resources/Textures/Markers/environment.rsi/weather.png differ
diff --git a/Resources/Textures/Shaders/flap.swsl b/Resources/Textures/Shaders/flap.swsl
new file mode 100644
index 0000000000..3082e19b49
--- /dev/null
+++ b/Resources/Textures/Shaders/flap.swsl
@@ -0,0 +1,35 @@
+preset raw;
+
+varying highp vec4 VtxModulate;
+varying highp vec2 Pos;
+
+uniform highp float Speed;
+uniform highp float Multiplier;
+uniform highp float Offset;
+
+void fragment() {
+ highp vec4 texColor = zTexture(UV);
+ lowp vec3 lightSample = texture2D(lightMap, Pos).rgb;
+ COLOR = texColor * VtxModulate * vec4(lightSample, 1.0);
+}
+
+void vertex() {
+ vec2 pos = aPos;
+
+ // Apply MVP transformation first
+ vec2 transformedPos = apply_mvp(pos);
+
+ // Calculate vertical movement in screen space
+ float verticalOffset = (sin(TIME * Speed) + Offset) * Multiplier;
+
+ // Apply vertical movement after MVP transformation
+ transformedPos.y += verticalOffset;
+
+ // Assign the final position
+ VERTEX = transformedPos;
+
+ // Keep the original UV coordinates
+ UV = mix(modifyUV.xy, modifyUV.zw, tCoord);
+ Pos = (VERTEX + 1.0) / 2.0;
+ VtxModulate = zFromSrgb(modulate);
+}
\ No newline at end of file