diff --git a/Content.Server/HeightAdjust/BloodstreamAdjustSystem.cs b/Content.Server/HeightAdjust/BloodstreamAdjustSystem.cs new file mode 100644 index 00000000000..92e03e0c111 --- /dev/null +++ b/Content.Server/HeightAdjust/BloodstreamAdjustSystem.cs @@ -0,0 +1,45 @@ +using Content.Server.Body.Components; +using Content.Server.Chemistry.Containers.EntitySystems; +using Content.Shared.CCVar; +using Content.Shared.Chemistry.Reagent; +using Content.Shared.Contests; +using Content.Shared.HeightAdjust; +using Robust.Shared.Configuration; + +namespace Content.Server.HeightAdjust; + +public sealed class BloodstreamAdjustSystem : EntitySystem +{ + [Dependency] private readonly IConfigurationManager _config = default!; + [Dependency] private readonly ContestsSystem _contests = default!; + [Dependency] private readonly SolutionContainerSystem _solutionContainer = default!; + + public override void Initialize() + { + SubscribeLocalEvent((uid, comp, _) => TryAdjustBloodstream((uid, comp))); + SubscribeLocalEvent((uid, comp, _) => TryAdjustBloodstream((uid, comp))); + } + + /// + /// Adjusts the bloodstream of the specified entity based on the settings provided by the component. + /// + public bool TryAdjustBloodstream(Entity ent) + { + if (!TryComp(ent, out var bloodstream) + || !_solutionContainer.TryGetSolution(ent.Owner, bloodstream.BloodSolutionName, out var bloodSolutionEnt) + || !_config.GetCVar(CCVars.HeightAdjustModifiesBloodstream)) + return false; + + var bloodSolution = bloodSolutionEnt.Value.Comp.Solution; + + var factor = Math.Pow(_contests.MassContest(ent, bypassClamp: true, rangeFactor: 4f), ent.Comp.Power); + factor = Math.Clamp(factor, ent.Comp.Min, ent.Comp.Max); + + var newVolume = bloodstream.BloodMaxVolume * factor; + var newBloodLevel = bloodSolution.FillFraction * newVolume; + bloodSolution.MaxVolume = newVolume; + bloodSolution.SetContents([new ReagentQuantity(bloodstream.BloodReagent, newBloodLevel, null)], false); + + return true; + } +} diff --git a/Content.Server/HeightAdjust/BloodstreamAffectedByMassComponent.cs b/Content.Server/HeightAdjust/BloodstreamAffectedByMassComponent.cs new file mode 100644 index 00000000000..f6c3a0e250c --- /dev/null +++ b/Content.Server/HeightAdjust/BloodstreamAffectedByMassComponent.cs @@ -0,0 +1,26 @@ +using Content.Server.Body.Components; + +namespace Content.Server.HeightAdjust; + +/// +/// When applied to a humanoid or any mob, adjusts their blood level based on the mass contest between them +/// and an average humanoid. +///
+/// The formula for the resulting bloodstream volume is V = BloodMaxVolume * MassContest^Power +/// clamped between the specified Min and Max values. +///
+[RegisterComponent] +public sealed partial class BloodstreamAffectedByMassComponent : Component +{ + /// + /// Minimum and maximum resulting volume factors. A minimum value of 0.5 means that the resulting volume will be at least 50% of the original. + /// + [DataField] + public float Min = 1 / 3f, Max = 3f; + + /// + /// The power to which the outcome of the mass contest will be risen. + /// + [DataField] + public float Power = 1f; +} diff --git a/Content.Server/InteractionVerbs/Actions/MoodAction.cs b/Content.Server/InteractionVerbs/Actions/MoodAction.cs new file mode 100644 index 00000000000..5b53c6ca18d --- /dev/null +++ b/Content.Server/InteractionVerbs/Actions/MoodAction.cs @@ -0,0 +1,42 @@ +using Content.Shared.InteractionVerbs; +using Content.Shared.Mood; +using Robust.Shared.Prototypes; + +namespace Content.Server.InteractionVerbs.Actions; + +/// +/// An action that adds a moodlet to the target, or removes one. +/// +[Serializable] +public sealed partial class MoodAction : InteractionAction +{ + [DataField(required: true)] + public ProtoId Effect; + + /// + /// Parameters for the . Only used if is false. + /// + [DataField] + public float Modifier = 1f, Offset = 0f; + + /// + /// If true, the moodlet will be removed. Otherwise, it will be added. + /// + [DataField] + public bool Remove = false; + + public override bool CanPerform(InteractionArgs args, InteractionVerbPrototype proto, bool isBefore, VerbDependencies deps) + { + return true; + } + + public override bool Perform(InteractionArgs args, InteractionVerbPrototype proto, VerbDependencies deps) + { + if (Remove) + deps.EntMan.EventBus.RaiseLocalEvent(args.Target, new MoodRemoveEffectEvent(Effect)); + else + deps.EntMan.EventBus.RaiseLocalEvent(args.Target, new MoodEffectEvent(Effect, Modifier, Offset)); + + return true; // Mood system is shitcode so we can't even know if the effect was added or anything + } +} diff --git a/Content.Server/StationEvents/Components/OscillatingStationEventSchedulerComponent.cs b/Content.Server/StationEvents/Components/OscillatingStationEventSchedulerComponent.cs new file mode 100644 index 00000000000..7f28401a5a9 --- /dev/null +++ b/Content.Server/StationEvents/Components/OscillatingStationEventSchedulerComponent.cs @@ -0,0 +1,69 @@ +namespace Content.Server.StationEvents.Components; + +/// +/// A station event scheduler that emits events at irregular intervals, with occasional chaos and occasional calmness. +/// +[RegisterComponent] +public sealed partial class OscillatingStationEventSchedulerComponent : Component +{ + // TODO cvars? + [DataField] + public float MinChaos = 0.1f, MaxChaos = 15f; + + /// + /// The amount of chaos at the beginning of the round. + /// + [DataField] + public float StartingChaosRatio = 0f; + + /// + /// The value of the first derivative of the event delay function at the beginning of the shift. + /// Must be between 1 and -1. + /// + [DataField] + public float StartingSlope = 1f; + + /// + /// Biases that determine how likely the event rate is to go up or down, and how fast it's going to happen. + /// + /// + /// Downwards bias must always be negative, and upwards must be positive. Otherwise, you'll get odd behavior or errors. + /// + [DataField] + public float DownwardsBias = -1f, UpwardsBias = 1f; + + /// + /// Limits that define how large the chaos slope can become. + /// + /// + /// Downwards limit must always be negative, and upwards must be positive. Otherwise, you'll get odd behavior or errors. + /// + [DataField] + public float DownwardsLimit = -1f, UpwardsLimit = 1f; + + /// + /// A value between 0 and 1 that determines how slowly the chaos and its first derivative change in time. + /// + /// + /// Changing these values will have a great impact on how fast the event rate changes. + /// + [DataField] + public float ChaosStickiness = 0.93f, SlopeStickiness = 0.96f; + + /// + /// Actual chaos data at the current moment. Those are overridden at runtime. + /// + [DataField] + public float CurrentChaos, CurrentSlope, LastAcceleration; + + + [DataField] + public TimeSpan NextUpdate = TimeSpan.Zero, LastEventTime = TimeSpan.Zero; + + /// + /// Update interval, which determines how often current chaos is recalculated. + /// Modifying this value does not directly impact the event rate, but changes how stable the slope is. + /// + [DataField] + public TimeSpan UpdateInterval = TimeSpan.FromSeconds(5f); +} diff --git a/Content.Server/StationEvents/OscillatingStationEventScheduler.cs b/Content.Server/StationEvents/OscillatingStationEventScheduler.cs new file mode 100644 index 00000000000..2cbf8613862 --- /dev/null +++ b/Content.Server/StationEvents/OscillatingStationEventScheduler.cs @@ -0,0 +1,102 @@ +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using Content.Server.GameTicking; +using Content.Server.GameTicking.Rules; +using Content.Server.GameTicking.Rules.Components; +using Content.Server.StationEvents.Components; +using Content.Shared.CCVar; +using Robust.Shared.Configuration; +using Robust.Shared.Random; +using Robust.Shared.Timing; +using Robust.Shared.Utility; + +namespace Content.Server.StationEvents; + +public sealed class OscillatingStationEventSchedulerSystem : GameRuleSystem +{ + [Dependency] private readonly IConfigurationManager _cfg = default!; + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly EventManagerSystem _event = default!; + [Dependency] private readonly GameTicker _gameTicker = default!; + [Dependency] private readonly IGameTiming _timing = default!; + + [Conditional("DEBUG")] + private void DebugValidateParams(OscillatingStationEventSchedulerComponent c) + { + // This monstrousity is necessary because if someone fucks up one of these parameters, + // it will likely either crash the game (in debug), or cause the event scheduler to stop working and spam the server console (in prod) + DebugTools.Assert(c.DownwardsBias <= 0f && c.UpwardsBias >= 0f, "Fix your scheduler bias"); + DebugTools.Assert(c.DownwardsLimit <= 0f && c.UpwardsLimit >= 0f, "Fix your scheduler slope limits"); + DebugTools.Assert(c.UpdateInterval > TimeSpan.Zero, "Scheduler update interval must be positive"); + DebugTools.Assert(c.ChaosStickiness >= 0f && c.ChaosStickiness <= 1f, "Scheduler stickiness must be between 0 and 1"); + DebugTools.Assert(c.SlopeStickiness >= 0f && c.SlopeStickiness <= 1f, "Scheduler stickiness must be between 0 and 1"); + DebugTools.Assert(c.MinChaos < c.MaxChaos, "Don't set the minimum above the maximum"); + } + + private TimeSpan CalculateAverageEventTime(OscillatingStationEventSchedulerComponent comp) + { + //TODO Those cvars are bad + var min = _cfg.GetCVar(CCVars.GameEventsOscillatingMinimumTime); + var max = _cfg.GetCVar(CCVars.GameEventsOscillatingAverageTime); + + return TimeSpan.FromSeconds(min + (max - min) / comp.CurrentChaos); // Why does C# have no math.lerp?????????????? + } + + protected override void Started(EntityUid uid, OscillatingStationEventSchedulerComponent comp, GameRuleComponent gameRule, GameRuleStartedEvent args) + { + DebugValidateParams(comp); + + comp.CurrentChaos = comp.MinChaos + comp.StartingChaosRatio * (comp.MaxChaos - comp.MinChaos); + comp.CurrentSlope = comp.StartingSlope; + + comp.NextUpdate = _timing.CurTime + CalculateAverageEventTime(comp); + comp.LastEventTime = _timing.CurTime; // Just so we don't run an event the very moment this scheduler gets added + } + + protected override void ActiveTick(EntityUid uid, OscillatingStationEventSchedulerComponent comp, GameRuleComponent gameRule, float frameTime) + { + if (comp.NextUpdate > _timing.CurTime) + return; + comp.NextUpdate = _timing.CurTime + comp.UpdateInterval; + DebugValidateParams(comp); + + // Slope is the first derivative of chaos, and acceleration is the second + // We randomize acceleration on each tick and simulate its effect on the slope and base function + // But we spread the effect across a longer time span to achieve a smooth and pleasant result + var delta = (float) comp.UpdateInterval.TotalSeconds; + var newAcceleration = _random.NextFloat(comp.DownwardsBias, comp.UpwardsBias); + var newSlope = + Math.Clamp(comp.CurrentSlope + newAcceleration * delta, comp.DownwardsLimit, comp.UpwardsLimit) * (1 - comp.SlopeStickiness) + + comp.CurrentSlope * comp.SlopeStickiness; + var newChaos = + Math.Clamp(comp.CurrentChaos + newSlope * delta, comp.MinChaos, comp.MaxChaos) * (1 - comp.ChaosStickiness) + + comp.CurrentChaos * comp.ChaosStickiness; + + comp.CurrentChaos = newChaos; + comp.CurrentSlope = newSlope; + comp.LastAcceleration = newAcceleration; + + // We do not use fixed "next event" times because that can cause us to skip over chaos spikes due to periods of low chaos + // Instead we recalculate the time until next event every time, so it can change before the event is even started + var targetDelay = CalculateAverageEventTime(comp); + if (_timing.CurTime > comp.LastEventTime + targetDelay && TryRunNextEvent(uid, comp, out _)) + { + #if DEBUG + var passed = _timing.CurTime - comp.LastEventTime; + Log.Debug($"Running an event after {passed.TotalSeconds} sec since last event. Next event scheduled in {CalculateAverageEventTime(comp).TotalSeconds} sec."); + #endif + + comp.LastEventTime = _timing.CurTime; + } + } + + public bool TryRunNextEvent(EntityUid uid, OscillatingStationEventSchedulerComponent comp, [NotNullWhen(true)] out string? runEvent) + { + runEvent = _event.PickRandomEvent(); + if (runEvent == null) + return false; + + _gameTicker.AddGameRule(runEvent); + return true; + } +} diff --git a/Content.Server/Traits/TraitSystem.cs b/Content.Server/Traits/TraitSystem.cs index ae8f8038534..d6f13cb52a9 100644 --- a/Content.Server/Traits/TraitSystem.cs +++ b/Content.Server/Traits/TraitSystem.cs @@ -24,6 +24,7 @@ public sealed class TraitSystem : EntitySystem [Dependency] private readonly IConfigurationManager _configuration = default!; [Dependency] private readonly SharedActionsSystem _actions = default!; [Dependency] private readonly PsionicAbilitiesSystem _psionicAbilities = default!; + [Dependency] private readonly IComponentFactory _componentFactory = default!; public override void Initialize() { @@ -60,11 +61,34 @@ private void OnPlayerSpawnComplete(PlayerSpawnCompleteEvent args) /// public void AddTrait(EntityUid uid, TraitPrototype traitPrototype) { + RemoveTraitComponents(uid, traitPrototype); AddTraitComponents(uid, traitPrototype); AddTraitActions(uid, traitPrototype); AddTraitPsionics(uid, traitPrototype); } + /// + /// Removes all components defined by a Trait. It's not possible to validate component removals, + /// so if an incorrect string is given, it's basically a skill issue. + /// + /// + /// This comes before AddTraitComponents for a good reason. + /// It allows for a component to optionally be fully wiped and replaced with a new component. + /// + public void RemoveTraitComponents(EntityUid uid, TraitPrototype traitPrototype) + { + if (traitPrototype.ComponentRemovals is null) + return; + + foreach (var entry in traitPrototype.ComponentRemovals) + { + if (!_componentFactory.TryGetRegistration(entry, out var comp)) + continue; + + EntityManager.RemoveComponent(uid, comp.Type); + } + } + /// /// Adds all Components included with a Trait. /// diff --git a/Content.Shared/CCVar/CCVars.cs b/Content.Shared/CCVar/CCVars.cs index 70517b55787..630a56f4c3c 100644 --- a/Content.Shared/CCVar/CCVars.cs +++ b/Content.Shared/CCVar/CCVars.cs @@ -178,28 +178,37 @@ public static readonly CVarDef /// Minimum time between Basic station events in seconds /// public static readonly CVarDef // 5 Minutes - GameEventsBasicMinimumTime = CVarDef.Create("game.events_basic_minimum_time", 300, CVar.SERVERONLY); + GameEventsBasicMinimumTime = CVarDef.Create("game.events_basic_minimum_time", 300, CVar.SERVERONLY | CVar.ARCHIVE); /// /// Maximum time between Basic station events in seconds /// public static readonly CVarDef // 25 Minutes - GameEventsBasicMaximumTime = CVarDef.Create("game.events_basic_maximum_time", 1500, CVar.SERVERONLY); + GameEventsBasicMaximumTime = CVarDef.Create("game.events_basic_maximum_time", 1500, CVar.SERVERONLY | CVar.ARCHIVE); /// /// Minimum time between Ramping station events in seconds /// public static readonly CVarDef // 4 Minutes - GameEventsRampingMinimumTime = CVarDef.Create("game.events_ramping_minimum_time", 240, CVar.SERVERONLY); + GameEventsRampingMinimumTime = CVarDef.Create("game.events_ramping_minimum_time", 240, CVar.SERVERONLY | CVar.ARCHIVE); /// /// Maximum time between Ramping station events in seconds /// public static readonly CVarDef // 12 Minutes - GameEventsRampingMaximumTime = CVarDef.Create("game.events_ramping_maximum_time", 720, CVar.SERVERONLY); + GameEventsRampingMaximumTime = CVarDef.Create("game.events_ramping_maximum_time", 720, CVar.SERVERONLY | CVar.ARCHIVE); /// - /// + /// Minimum time between Oscillating station events in seconds. This is the bare minimum which will never be violated, unlike with ramping events. + /// + public static readonly CVarDef // 40 seconds + GameEventsOscillatingMinimumTime = CVarDef.Create("game.events_oscillating_minimum_time", 40, CVar.SERVERONLY | CVar.ARCHIVE); + + /// + /// Time between Oscillating station events in seconds at 1x chaos level. Events may occur at larger intervals if current chaos is lower than that. + /// + public static readonly CVarDef // 20 Minutes - which constitutes a minimum of 120 seconds between events in Irregular and 280 seconds in Extended Irregular + GameEventsOscillatingAverageTime = CVarDef.Create("game.events_oscillating_average_time", 1200, CVar.SERVERONLY | CVar.ARCHIVE); /// /// Controls the maximum number of character slots a player is allowed to have. @@ -402,6 +411,12 @@ public static readonly CVarDef 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. + /// + public static readonly CVarDef AllowSlotQuickSwap = + CVarDef.Create("game.slot_quick_swap", false, CVar.REPLICATED); + #if EXCEPTION_TOLERANCE /// /// Amount of times round start must fail before the server is shut down. @@ -2341,6 +2356,15 @@ public static readonly CVarDef public static readonly CVarDef HeightAdjustModifiesZoom = CVarDef.Create("heightadjust.modifies_zoom", false, CVar.SERVERONLY); + /// + /// Whether height & width sliders adjust a player's bloodstream volume. + /// + /// + /// This can be configured more precisely by modifying BloodstreamAffectedByMassComponent. + /// + public static readonly CVarDef HeightAdjustModifiesBloodstream = + CVarDef.Create("heightadjust.modifies_bloodstream", true, CVar.SERVERONLY); + /// /// Enables station goals /// diff --git a/Content.Shared/Containers/ItemSlot/ItemSlotsComponent.cs b/Content.Shared/Containers/ItemSlot/ItemSlotsComponent.cs index 42e7f721b3e..ba8a9a934e4 100644 --- a/Content.Shared/Containers/ItemSlot/ItemSlotsComponent.cs +++ b/Content.Shared/Containers/ItemSlot/ItemSlotsComponent.cs @@ -214,6 +214,7 @@ public ItemSlot(ItemSlot other) /// /// If the user interacts with an entity with an already-filled item slot, should they attempt to swap out the item? + /// If set to null, will be deduced based on the relevant config variable. /// /// /// Useful for things like chem dispensers, but undesirable for things like the ID card console, where you @@ -221,7 +222,7 @@ public ItemSlot(ItemSlot other) /// [DataField] [Access(typeof(ItemSlotsSystem), Other = AccessPermissions.ReadWriteExecute)] - public bool Swap = true; + public bool? Swap = null; public string? ID => ContainerSlot?.ID; diff --git a/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs b/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs index 9cb21e882e3..c7932ef8f75 100644 --- a/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs +++ b/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs @@ -1,6 +1,7 @@ using System.Diagnostics.CodeAnalysis; using Content.Shared.ActionBlocker; using Content.Shared.Administration.Logs; +using Content.Shared.CCVar; using Content.Shared.Database; using Content.Shared.Destructible; using Content.Shared.Hands.Components; @@ -10,6 +11,7 @@ using Content.Shared.Popups; using Content.Shared.Verbs; using Robust.Shared.Audio.Systems; +using Robust.Shared.Configuration; using Robust.Shared.Containers; using Robust.Shared.GameStates; using Robust.Shared.Utility; @@ -27,11 +29,14 @@ public sealed class ItemSlotsSystem : EntitySystem { [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; [Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!; + [Dependency] private readonly IConfigurationManager _config = default!; [Dependency] private readonly SharedContainerSystem _containers = default!; [Dependency] private readonly SharedPopupSystem _popupSystem = default!; [Dependency] private readonly SharedHandsSystem _handsSystem = default!; [Dependency] private readonly SharedAudioSystem _audioSystem = default!; + private bool _defaultQuickSwap; + public override void Initialize() { base.Initialize(); @@ -53,6 +58,8 @@ public override void Initialize() SubscribeLocalEvent(HandleItemSlotsState); SubscribeLocalEvent(HandleButtonPressed); + + _config.OnValueChanged(CCVars.AllowSlotQuickSwap, b => _defaultQuickSwap = b, true); } #region ComponentManagement @@ -202,7 +209,7 @@ private void OnInteractUsing(EntityUid uid, ItemSlotsComponent itemSlots, Intera if (!slot.InsertOnInteract) continue; - if (!CanInsert(uid, args.Used, args.User, slot, swap: slot.Swap, popup: args.User)) + if (!CanInsert(uid, args.Used, args.User, slot, swap: slot.Swap ?? _defaultQuickSwap, popup: args.User)) continue; // Drop the held item onto the floor. Return if the user cannot drop. diff --git a/Content.Shared/HeightAdjust/HeightAdjustSystem.cs b/Content.Shared/HeightAdjust/HeightAdjustSystem.cs index 46b2d9b656f..8bfdaccfd13 100644 --- a/Content.Shared/HeightAdjust/HeightAdjustSystem.cs +++ b/Content.Shared/HeightAdjust/HeightAdjustSystem.cs @@ -25,27 +25,7 @@ public sealed class HeightAdjustSystem : EntitySystem /// True if all operations succeeded public bool SetScale(EntityUid uid, float scale) { - var succeeded = true; - if (_config.GetCVar(CCVars.HeightAdjustModifiesZoom) && EntityManager.TryGetComponent(uid, out var eye)) - _eye.SetMaxZoom(uid, eye.MaxZoom * scale); - else - succeeded = false; - - if (_config.GetCVar(CCVars.HeightAdjustModifiesHitbox) && EntityManager.TryGetComponent(uid, out var fixtures)) - foreach (var fixture in fixtures.Fixtures) - _physics.SetRadius(uid, fixture.Key, fixture.Value, fixture.Value.Shape, MathF.MinMagnitude(fixture.Value.Shape.Radius * scale, 0.49f)); - else - succeeded = false; - - if (EntityManager.HasComponent(uid)) - { - _appearance.SetHeight(uid, scale); - _appearance.SetWidth(uid, scale); - } - else - succeeded = false; - - return succeeded; + return SetScale(uid, new Vector2(scale, scale)); } /// @@ -75,6 +55,8 @@ public bool SetScale(EntityUid uid, Vector2 scale) else succeeded = false; + RaiseLocalEvent(uid, new HeightAdjustedEvent { NewScale = scale }); + return succeeded; } } diff --git a/Content.Shared/HeightAdjust/HeightAdjustedEvent.cs b/Content.Shared/HeightAdjust/HeightAdjustedEvent.cs new file mode 100644 index 00000000000..3db856e0d83 --- /dev/null +++ b/Content.Shared/HeightAdjust/HeightAdjustedEvent.cs @@ -0,0 +1,11 @@ +using System.Numerics; + +namespace Content.Shared.HeightAdjust; + +/// +/// Raised on a humanoid after their scale has been adjusted in accordance with their profile and their physics have been updated. +/// +public sealed class HeightAdjustedEvent : EntityEventArgs +{ + public Vector2 NewScale; +} diff --git a/Content.Shared/InteractionVerbs/Requirements/AssortedRequirements.cs b/Content.Shared/InteractionVerbs/Requirements/AssortedRequirements.cs index 50c5c77d2cc..69193a9212c 100644 --- a/Content.Shared/InteractionVerbs/Requirements/AssortedRequirements.cs +++ b/Content.Shared/InteractionVerbs/Requirements/AssortedRequirements.cs @@ -13,11 +13,12 @@ namespace Content.Shared.InteractionVerbs.Requirements; [Serializable, NetSerializable] public sealed partial class EntityWhitelistRequirement : InteractionRequirement { - [DataField] public EntityWhitelist Whitelist = new(), Blacklist = new(); + [DataField] public EntityWhitelist? Whitelist, Blacklist; public override bool IsMet(InteractionArgs args, InteractionVerbPrototype proto, InteractionAction.VerbDependencies deps) { - return Whitelist.IsValid(args.Target, deps.EntMan) && !Blacklist.IsValid(args.Target, deps.EntMan); + return Whitelist?.IsValid(args.Target, deps.EntMan) != false + && Blacklist?.IsValid(args.Target, deps.EntMan) != true; } } diff --git a/Content.Shared/Traits/Assorted/Components/NormalVisionComponent.cs b/Content.Shared/Traits/Assorted/Components/NormalVisionComponent.cs deleted file mode 100644 index 442bb6f0084..00000000000 --- a/Content.Shared/Traits/Assorted/Components/NormalVisionComponent.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Robust.Shared.GameStates; - -namespace Content.Shared.Traits.Assorted.Components; - -/// -/// This is used for removing species specific vision traits -/// -[RegisterComponent, NetworkedComponent] -public sealed partial class NormalVisionComponent : Component -{ -} - diff --git a/Content.Shared/Traits/Assorted/Systems/NormalVisionSystem.cs b/Content.Shared/Traits/Assorted/Systems/NormalVisionSystem.cs deleted file mode 100644 index ee25bf364b9..00000000000 --- a/Content.Shared/Traits/Assorted/Systems/NormalVisionSystem.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Content.Shared.Abilities; -using Content.Shared.Traits.Assorted.Components; - -namespace Content.Shared.Traits.Assorted.Systems; - -/// -/// This handles removing species-specific vision traits. -/// -public sealed class NormalVisionSystem : EntitySystem -{ - /// - public override void Initialize() - { - SubscribeLocalEvent(OnStartup); - } - - - private void OnStartup(EntityUid uid, NormalVisionComponent component, ComponentInit args) - { - RemComp(uid); - RemComp(uid); - } -} diff --git a/Content.Shared/Traits/Prototypes/TraitPrototype.cs b/Content.Shared/Traits/Prototypes/TraitPrototype.cs index 8aa3e4442f0..7bdff058ee9 100644 --- a/Content.Shared/Traits/Prototypes/TraitPrototype.cs +++ b/Content.Shared/Traits/Prototypes/TraitPrototype.cs @@ -38,6 +38,13 @@ public sealed partial class TraitPrototype : IPrototype [DataField] public ComponentRegistry? Components { get; private set; } = default!; + /// + /// The components that will be removed from a player when they pick this trait. + /// Primarily used to remove species innate traits. + /// + [DataField] + public List? ComponentRemovals { get; private set; } = default!; + /// /// The list of each Action that this trait adds in the form of ActionId and ActionEntity /// diff --git a/Resources/Audio/StationEvents/attributions.yml b/Resources/Audio/StationEvents/attributions.yml index e63b18a627f..9b3ad134841 100644 --- a/Resources/Audio/StationEvents/attributions.yml +++ b/Resources/Audio/StationEvents/attributions.yml @@ -6,4 +6,9 @@ - files: ["clearly_nuclear.ogg"] license: "CC-BY-3.0" copyright: "Created by mryikes" - source: "https://www.youtube.com/watch?v=chix8uz-oUQ" \ No newline at end of file + source: "https://www.youtube.com/watch?v=chix8uz-oUQ" + +- files: ["chip_nightmare.ogg"] + license: "CC-BY-SA-4.0" + copyright: "Created by BasedUser on top of chip-meltdown.mod by Reanimator (Thom)." + source: "http://ygg.baseduser.eu.org/chip-nightmare_ss14.ogg" diff --git a/Resources/Audio/StationEvents/chip_nightmare.ogg b/Resources/Audio/StationEvents/chip_nightmare.ogg new file mode 100644 index 00000000000..c721c0ca24a Binary files /dev/null and b/Resources/Audio/StationEvents/chip_nightmare.ogg differ diff --git a/Resources/Audio/Voice/Slime/slime_scream_f2.ogg b/Resources/Audio/Voice/Slime/slime_scream_f2.ogg index 71ea5f4bdce..923da501667 100644 Binary files a/Resources/Audio/Voice/Slime/slime_scream_f2.ogg and b/Resources/Audio/Voice/Slime/slime_scream_f2.ogg differ diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 7269a9a2db8..7f13cc1e78b 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -5985,3 +5985,29 @@ Entries: id: 6325 time: '2024-09-07T03:59:44.0000000+00:00' url: https://github.com/Simple-Station/Einstein-Engines/pull/861 +- author: Mnemotechnician + changes: + - type: Add + message: >- + Your character size now affects your blood level. Smaller characters + will have less blood, and larger characters will have more. + id: 6326 + time: '2024-09-08T14:39:19.0000000+00:00' + url: https://github.com/Simple-Station/Einstein-Engines/pull/858 +- author: Mnemotechnician + changes: + - type: Remove + message: >- + Quick swap has been disabled for most item slots. This primarily means + you will have to eject power cells/magazines from items/weapons/borgs + before replacing them with different ones. + id: 6327 + time: '2024-09-08T14:42:30.0000000+00:00' + url: https://github.com/Simple-Station/Einstein-Engines/pull/856 +- author: router + changes: + - type: Tweak + message: Female slimes no longer have movie screams. + id: 6328 + time: '2024-09-08T14:44:29.0000000+00:00' + url: https://github.com/Simple-Station/Einstein-Engines/pull/849 diff --git a/Resources/Locale/en-US/devices/device-network.ftl b/Resources/Locale/en-US/devices/device-network.ftl index eb6072fd72e..2740143d519 100644 --- a/Resources/Locale/en-US/devices/device-network.ftl +++ b/Resources/Locale/en-US/devices/device-network.ftl @@ -31,7 +31,7 @@ device-address-prefix-freezer = FZR- device-address-prefix-volume-pump = VPP- device-address-prefix-smes = SMS- -# PDAs and terminals #floof +# PDAs and terminals device-address-prefix-console = CLS- device-address-prefix-fire-alarm = FIR- device-address-prefix-air-alarm = AIR- @@ -40,7 +40,7 @@ device-address-prefix-sensor-monitor = MON- device-address-examine-message = The device's address is {$address}. -# Device net ID names #floof +# Device net ID names device-net-id-private = Private device-net-id-wired = Wired device-net-id-wireless = Wireless diff --git a/Resources/Locale/en-US/game-ticking/game-presets/preset-irregular.ftl b/Resources/Locale/en-US/game-ticking/game-presets/preset-irregular.ftl new file mode 100644 index 00000000000..35fc7957cf2 --- /dev/null +++ b/Resources/Locale/en-US/game-ticking/game-presets/preset-irregular.ftl @@ -0,0 +1,5 @@ +irregular-title = Irregular +irregular-description = Threat level varies throughout the shift. Sometimes it's a paradise, sometimes it's a disaster. + +irregular-extended-title = Irregular Extended +irregular-extended-description = A rather calm experience with occasional spikes of threats. diff --git a/Resources/Locale/en-US/interaction/verbs/noop.ftl b/Resources/Locale/en-US/interaction/verbs/noop.ftl index 579f0b8309b..953b2808ecb 100644 --- a/Resources/Locale/en-US/interaction/verbs/noop.ftl +++ b/Resources/Locale/en-US/interaction/verbs/noop.ftl @@ -16,6 +16,12 @@ interaction-Pet-success-self-popup = You pet {THE($target)} on {POSS-ADJ($target interaction-Pet-success-target-popup = {THE($user)} pets you on your head. interaction-Pet-success-others-popup = {THE($user)} pets {THE($target)}. +interaction-PetAnimal-name = {interaction-Pet-name} +interaction-PetAnimal-description = Pet an animal. +interaction-PetAnimal-success-self-popup = {interaction-Pet-success-self-popup} +interaction-PetAnimal-success-target-popup = {interaction-Pet-success-target-popup} +interaction-PetAnimal-success-others-popup = {interaction-Pet-success-others-popup} + interaction-KnockOn-name = Knock interaction-KnockOn-description = Knock on the target to attract attention. interaction-KnockOn-success-self-popup = You knock on {THE($target)}. diff --git a/Resources/Locale/en-US/mood/mood.ftl b/Resources/Locale/en-US/mood/mood.ftl index c12ec7246ec..bd64d525820 100644 --- a/Resources/Locale/en-US/mood/mood.ftl +++ b/Resources/Locale/en-US/mood/mood.ftl @@ -37,6 +37,8 @@ mood-effect-Dead = You are dead. mood-effect-BeingHugged = Hugs are nice. +mood-effect-BeingPet = Someone pet me! + mood-effect-ArcadePlay = I had fun playing an interesting arcade game. mood-effect-GotBlessed = I was blessed. @@ -51,4 +53,4 @@ 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! \ No newline at end of file +mood-effect-TraitSanguine = I have nothing to worry about. I'm sure everything will turn out well in the end! diff --git a/Resources/Locale/en-US/reagents/meta/consumable/drink/alcohol.ftl b/Resources/Locale/en-US/reagents/meta/consumable/drink/alcohol.ftl index 524e05e3b18..682e03ff772 100644 --- a/Resources/Locale/en-US/reagents/meta/consumable/drink/alcohol.ftl +++ b/Resources/Locale/en-US/reagents/meta/consumable/drink/alcohol.ftl @@ -37,8 +37,8 @@ reagent-desc-poison-wine = Is this even wine? Toxic! Hallucinogenic! Probably co reagent-name-rum = rum reagent-desc-rum = Distilled alcoholic drink made from sugarcane byproducts. -# reagent-name-sake = sake #floof -# reagent-desc-sake = Alcoholic beverage made by fermenting rice that has been polished. #floof +# reagent-name-sake = sake +# reagent-desc-sake = Alcoholic beverage made by fermenting rice that has been polished. reagent-name-tequila = tequila reagent-desc-tequila = A strong and mildly flavoured, mexican produced spirit. diff --git a/Resources/Locale/en-US/revenant/revenant.ftl b/Resources/Locale/en-US/revenant/revenant.ftl index 4c76fbea137..b13858be743 100644 --- a/Resources/Locale/en-US/revenant/revenant.ftl +++ b/Resources/Locale/en-US/revenant/revenant.ftl @@ -16,7 +16,7 @@ revenant-soul-yield-low = {CAPITALIZE(THE($target))} has a below average soul. revenant-soul-begin-harvest = {CAPITALIZE(THE($target))} suddenly rises slightly into the air, {POSS-ADJ($target)} skin turning an ashy gray. revenant-soul-finish-harvest = {CAPITALIZE(THE($target))} slumps onto the ground! -# UI #floof +# UI revenant-user-interface-title = Ability Shop revenant-user-interface-essence-amount = [color=plum]{$amount}[/color] Stolen Essence diff --git a/Resources/Locale/en-US/traits/traits.ftl b/Resources/Locale/en-US/traits/traits.ftl index 139996fa7f9..5c404a7fb29 100644 --- a/Resources/Locale/en-US/traits/traits.ftl +++ b/Resources/Locale/en-US/traits/traits.ftl @@ -216,3 +216,9 @@ trait-description-NaturalTelepath = whether or not you possess any notable psychic powers. This offers all of the same benefits and drawbacks of Latent Psychic, except that you are guaranteed to start with full Telepathy. You may still gain powers as normal for a Latent Psychic. + +trait-name-AnomalousPositronics = Anomalous Positronics +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. diff --git a/Resources/Locale/en-US/weapons/melee/melee.ftl b/Resources/Locale/en-US/weapons/melee/melee.ftl index 93a36a97219..d3318ea2449 100644 --- a/Resources/Locale/en-US/weapons/melee/melee.ftl +++ b/Resources/Locale/en-US/weapons/melee/melee.ftl @@ -3,5 +3,5 @@ melee-inject-failed-hardsuit = Your {$weapon} cannot inject through hardsuits! melee-balloon-pop = {CAPITALIZE(THE($balloon))} popped! -# BatteryComponent #floof +# BatteryComponent melee-battery-examine = It has enough charge for [color={$color}]{$count}[/color] hits. diff --git a/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/fun.yml b/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/fun.yml new file mode 100644 index 00000000000..96008395b3a --- /dev/null +++ b/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/fun.yml @@ -0,0 +1,63 @@ +- type: entity + name: space shrimp + parent: [ SimpleMobBase, FlyingMobBase, MobCombat ] + id: MobSpaceShrimp + description: Shrimply cursed... + components: + - type: MeleeWeapon + soundHit: + path: /Audio/Effects/pop.ogg + - type: MovementSpeedModifier + baseWalkSpeed : 6 + baseSprintSpeed : 6 + - type: Sprite + sprite: DeltaV/Mobs/Animals/shrimp.rsi + layers: + - map: ["enum.DamageStateVisualLayers.Base"] + state: shrimp + - type: Fixtures + fixtures: + fix1: + shape: + !type:PhysShapeCircle + radius: 0.35 + density: 100 + mask: + - FlyingMobMask + layer: + - FlyingMobLayer + - type: Physics + - type: DamageStateVisuals + states: + Alive: + Base: shrimp + Dead: + Base: dead + - type: Butcherable + spawned: + - id: FoodMeatCrab + amount: 3 + - type: Bloodstream + bloodMaxVolume: 100 + bloodReagent: BbqSauce # Australia reference + - type: InteractionPopup + successChance: 0.5 + interactSuccessString: petting-success-possum + interactFailureString: petting-failure-possum + interactSuccessSpawn: EffectHearts + interactSuccessSound: + path: /Audio/Animals/raccoon_chatter.ogg + - type: Speech + speechSounds: Slime + - type: Puller + needsHands: false + - type: MindContainer + showExamineInfo: true + - type: NpcFactionMember + factions: + - Passive + - type: Body + prototype: Animal + - type: HTN + rootTask: + task: SimpleHostileCompound diff --git a/Resources/Prototypes/Entities/Mobs/Species/base.yml b/Resources/Prototypes/Entities/Mobs/Species/base.yml index 8200f0cdbff..33635eeec20 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/base.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/base.yml @@ -309,6 +309,8 @@ - type: OfferItem - type: LayingDown - type: Shoving + - type: BloodstreamAffectedByMass + power: 0.6 # A minimum size felinid will have 30% blood, a minimum size vulp will have 60%, a maximum size oni will have ~200% - type: entity save: false diff --git a/Resources/Prototypes/GameRules/roundstart.yml b/Resources/Prototypes/GameRules/roundstart.yml index 0af55a7f9d0..0a9daeb4a80 100644 --- a/Resources/Prototypes/GameRules/roundstart.yml +++ b/Resources/Prototypes/GameRules/roundstart.yml @@ -142,6 +142,33 @@ startingChaosRatio: 0.025 # Starts as slow as survival, but quickly ramps up shiftLengthModifier: 2.5 +- type: entity + id: IrregularStationEventScheduler + parent: BaseGameRule + noSpawn: true + components: + - type: OscillatingStationEventScheduler + minChaos: 0.8 + maxChaos: 14 + startingSlope: 0.2 + downwardsLimit: -0.35 + upwardsLimit: 0.4 + +# More likely to go down than up, so calmness prevails +- type: entity + id: IrregularExtendedStationEventScheduler + parent: BaseGameRule + noSpawn: true + components: + - type: OscillatingStationEventScheduler + minChaos: 0.8 + maxChaos: 8 + startingSlope: -1 + downwardsLimit: -0.4 + upwardsLimit: 0.3 + downwardsBias: -1.1 + upwardsBias: 0.9 + # variation passes - type: entity id: BasicRoundstartVariation diff --git a/Resources/Prototypes/Interactions/mood_interactions.yml b/Resources/Prototypes/Interactions/mood_interactions.yml new file mode 100644 index 00000000000..6a50704b035 --- /dev/null +++ b/Resources/Prototypes/Interactions/mood_interactions.yml @@ -0,0 +1,60 @@ +# Hugging - improves the mood of the user +- type: Interaction + id: Hug + parent: [BaseGlobal, BaseHands] + priority: 2 + #icon: /Textures/Interface/Actions/hug.png + delay: 0.7 + range: {max: 1} + hideByRequirement: true + requirement: + !type:MobStateRequirement + inverted: true + action: + # TODO: this should pull the target closer or sumth, but I need to code that action first + !type:MoodAction + effect: BeingHugged + +# Petting someone (people) - improves the mood of the target +- type: Interaction + id: Pet + parent: [BaseGlobal, BaseHands] + priority: 1 + #icon: /Textures/Interface/Actions/hug.png + delay: 0.4 + range: {max: 1} + hideByRequirement: true + requirement: + !type:ComplexRequirement + requirements: + - !type:MobStateRequirement + inverted: true + - !type:EntityWhitelistRequirement + whitelist: + components: [HumanoidAppearance] + action: + !type:MoodAction + effect: BeingPet + +# Petting someone (animals) - improves the mood of the user and the target +- type: Interaction + id: PetAnimal + parent: Pet + requirement: + !type:ComplexRequirement + requirements: + - !type:MobStateRequirement + allowedStates: [Alive] + - !type:EntityWhitelistRequirement + blacklist: + components: [HumanoidAppearance] + action: + !type:ComplexAction # TODO might wanna make a multiplexer action for situations like this + actions: + - !type:MoodAction + effect: BeingPet + - !type:OnUserAction + action: + !type:MoodAction + effect: PetAnimal + diff --git a/Resources/Prototypes/Interactions/noop_interactions.yml b/Resources/Prototypes/Interactions/noop_interactions.yml index 573f1f77919..6729b36e75c 100644 --- a/Resources/Prototypes/Interactions/noop_interactions.yml +++ b/Resources/Prototypes/Interactions/noop_interactions.yml @@ -33,35 +33,6 @@ action: !type:NoOpAction -- type: Interaction - id: Hug - parent: [BaseGlobal, BaseHands] - priority: 2 - #icon: /Textures/Interface/Actions/hug.png - delay: 0.7 - range: {max: 1} - hideByRequirement: true - requirement: - !type:MobStateRequirement - inverted: true - action: - # TODO: this should pull the target closer or sumth, but I need to code that action first - !type:NoOpAction - -- type: Interaction - id: Pet - parent: [BaseGlobal, BaseHands] - priority: 1 - #icon: /Textures/Interface/Actions/hug.png - delay: 0.4 - range: {max: 1} - hideByRequirement: true - requirement: - !type:MobStateRequirement - inverted: true - action: - !type:NoOpAction - # Knocking on the target - windows, doors, etc. - type: Interaction id: KnockOn diff --git a/Resources/Prototypes/Mood/genericPositiveEffects.yml b/Resources/Prototypes/Mood/genericPositiveEffects.yml index 8ac5b25dc12..a4d5ae6ce05 100644 --- a/Resources/Prototypes/Mood/genericPositiveEffects.yml +++ b/Resources/Prototypes/Mood/genericPositiveEffects.yml @@ -2,6 +2,13 @@ id: BeingHugged moodChange: 3 timeout: 120 + category: PositiveInteraction + +- type: moodEffect + id: BeingPet + moodChange: 3 + timeout: 120 + category: PositiveInteraction - type: moodEffect id: ArcadePlay @@ -37,4 +44,4 @@ - type: moodEffect id: TraitSanguine - moodChange: 15 \ No newline at end of file + moodChange: 15 diff --git a/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Epistemics/forensicmantis.yml b/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Epistemics/forensicmantis.yml index 444465c84e4..a66bfee8d08 100644 --- a/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Epistemics/forensicmantis.yml +++ b/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Epistemics/forensicmantis.yml @@ -8,7 +8,16 @@ min: 3600 # 1hr floof - !type:DepartmentTimeRequirement department: Epistemics # DeltaV - Epistemics Department replacing Science - min: 3600 # 1 hr floof + min: 3600 + - !type:CharacterLogicOrRequirement + requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: + - IPC + - !type:CharacterTraitRequirement + traits: + - AnomalousPositronics startingGear: ForensicMantisGear icon: "JobIconForensicMantis" supervisors: job-supervisors-rd diff --git a/Resources/Prototypes/Nyanotrasen/metempsychoticNonHumanoids.yml b/Resources/Prototypes/Nyanotrasen/metempsychoticNonHumanoids.yml index feabd9977bc..00114644412 100644 --- a/Resources/Prototypes/Nyanotrasen/metempsychoticNonHumanoids.yml +++ b/Resources/Prototypes/Nyanotrasen/metempsychoticNonHumanoids.yml @@ -7,3 +7,4 @@ MobXenoQueen: 0.01 MobCrab: 0.01 MobPenguin: 1 + MobSpaceShrimp: 1 diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/chaplain.yml b/Resources/Prototypes/Roles/Jobs/Civilian/chaplain.yml index 837b3e37163..a2382a785d0 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/chaplain.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/chaplain.yml @@ -3,6 +3,16 @@ name: job-name-chaplain description: job-description-chaplain playTimeTracker: JobChaplain + requirements: + - !type:CharacterLogicOrRequirement + requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: + - IPC + - !type:CharacterTraitRequirement + traits: + - AnomalousPositronics startingGear: ChaplainGear icon: "JobIconChaplain" supervisors: job-supervisors-rd diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/librarian.yml b/Resources/Prototypes/Roles/Jobs/Civilian/librarian.yml index d93518d4eea..0ed78337020 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/librarian.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/librarian.yml @@ -7,6 +7,15 @@ - !type:CharacterDepartmentTimeRequirement department: Epistemics min: 3600 + - !type:CharacterLogicOrRequirement + requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: + - IPC + - !type:CharacterTraitRequirement + traits: + - AnomalousPositronics startingGear: LibrarianGear icon: "JobIconLibrarian" supervisors: job-supervisors-rd diff --git a/Resources/Prototypes/Roles/Jobs/Science/research_director.yml b/Resources/Prototypes/Roles/Jobs/Science/research_director.yml index 10dec227866..66626a7fbd7 100644 --- a/Resources/Prototypes/Roles/Jobs/Science/research_director.yml +++ b/Resources/Prototypes/Roles/Jobs/Science/research_director.yml @@ -8,6 +8,15 @@ - !type:CharacterDepartmentTimeRequirement department: Epistemics # DeltaV - Epistemics Department replacing Science min: 14400 # Floofstation - 4 hour + - !type:CharacterLogicOrRequirement + requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: + - IPC + - !type:CharacterTraitRequirement + traits: + - AnomalousPositronics weight: 10 startingGear: ResearchDirectorGear icon: "JobIconResearchDirector" diff --git a/Resources/Prototypes/SoundCollections/NukeMusic.yml b/Resources/Prototypes/SoundCollections/NukeMusic.yml index 51782d8bd55..b1017191392 100644 --- a/Resources/Prototypes/SoundCollections/NukeMusic.yml +++ b/Resources/Prototypes/SoundCollections/NukeMusic.yml @@ -3,4 +3,5 @@ files: - /Audio/StationEvents/running_out.ogg - /Audio/StationEvents/countdown.ogg - - /Audio/StationEvents/clearly_nuclear.ogg \ No newline at end of file + - /Audio/StationEvents/clearly_nuclear.ogg + - /Audio/StationEvents/chip_nightmare.ogg diff --git a/Resources/Prototypes/Traits/neutral.yml b/Resources/Prototypes/Traits/neutral.yml index 947f02361e0..b9f988106d3 100644 --- a/Resources/Prototypes/Traits/neutral.yml +++ b/Resources/Prototypes/Traits/neutral.yml @@ -36,8 +36,9 @@ species: - Harpy - Vulpkanin - components: - - type: NormalVision + componentRemovals: + - UltraVision + - DogVision - type: trait id: Saturnine diff --git a/Resources/Prototypes/Traits/skills.yml b/Resources/Prototypes/Traits/skills.yml index d0b6968f18d..0f0d9f8e990 100644 --- a/Resources/Prototypes/Traits/skills.yml +++ b/Resources/Prototypes/Traits/skills.yml @@ -188,10 +188,15 @@ - ForensicMantis - Chaplain - Librarian - - !type:CharacterSpeciesRequirement - inverted: true - species: - - IPC + - !type:CharacterLogicOrRequirement + requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: + - IPC + - !type:CharacterTraitRequirement + traits: + - AnomalousPositronics - !type:CharacterTraitRequirement inverted: true traits: @@ -214,14 +219,18 @@ - ForensicMantis - Chaplain - Librarian - - !type:CharacterSpeciesRequirement - inverted: true - species: - - IPC + - !type:CharacterLogicOrRequirement + requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: + - IPC + - !type:CharacterTraitRequirement + traits: + - AnomalousPositronics - !type:CharacterTraitRequirement inverted: true traits: - - Uncloneable - LatentPsychic - type: trait @@ -231,13 +240,37 @@ psionicPowers: - TelepathyPower requirements: - - !type:CharacterTraitRequirement - traits: - - LatentPsychic - !type:CharacterJobRequirement inverted: true jobs: - ResearchDirector - ForensicMantis - - Chaplain - - Librarian + - !type:CharacterLogicOrRequirement + requirements: + - !type:CharacterTraitRequirement + traits: + - LatentPsychic + - !type:CharacterJobRequirement + jobs: + - Chaplain + - Librarian + - !type:CharacterLogicOrRequirement + requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: + - IPC + - !type:CharacterTraitRequirement + traits: + - AnomalousPositronics + +- type: trait + id: AnomalousPositronics + category: Mental + points: -4 + componentRemovals: + - PsionicInsulation + requirements: + - !type:CharacterSpeciesRequirement + species: + - IPC diff --git a/Resources/Prototypes/game_presets.yml b/Resources/Prototypes/game_presets.yml index ebe2a7b02f9..12cdc167aa5 100644 --- a/Resources/Prototypes/game_presets.yml +++ b/Resources/Prototypes/game_presets.yml @@ -22,6 +22,26 @@ - BasicRoundstartVariation - SubGamemodesRule +- type: gamePreset + id: SurvivalIrregular + alias: [irregular] + showInVote: true + name: irregular-title + description: irregular-description + rules: + - IrregularStationEventScheduler + - BasicRoundstartVariation + +- type: gamePreset + id: SurvivalIrregularExtended + alias: [irregular-extended] + showInVote: true + name: irregular-extended-title + description: irregular-extended-description + rules: + - IrregularExtendedStationEventScheduler + - BasicRoundstartVariation + - type: gamePreset id: AllAtOnce name: all-at-once-title diff --git a/Resources/Textures/DeltaV/Mobs/Animals/shrimp.rsi/dead.png b/Resources/Textures/DeltaV/Mobs/Animals/shrimp.rsi/dead.png new file mode 100644 index 00000000000..f6f1cff31f5 Binary files /dev/null and b/Resources/Textures/DeltaV/Mobs/Animals/shrimp.rsi/dead.png differ diff --git a/Resources/Textures/DeltaV/Mobs/Animals/shrimp.rsi/meta.json b/Resources/Textures/DeltaV/Mobs/Animals/shrimp.rsi/meta.json new file mode 100644 index 00000000000..0bf79dc66f5 --- /dev/null +++ b/Resources/Textures/DeltaV/Mobs/Animals/shrimp.rsi/meta.json @@ -0,0 +1,24 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Sprite by Leonardo-DaBepis", + "states": [ + { + "name": "shrimp", + "directions": 4, + "delays": [ + [ 0.3, 0.4, 0.5, 0.3 ], + [ 0.3, 0.4, 0.5, 0.3 ], + [ 0.3, 0.4, 0.5, 0.3 ], + [ 0.3, 0.4, 0.5, 0.3 ] + ] + }, + { + "name": "dead" + } + ] +} diff --git a/Resources/Textures/DeltaV/Mobs/Animals/shrimp.rsi/shrimp.png b/Resources/Textures/DeltaV/Mobs/Animals/shrimp.rsi/shrimp.png new file mode 100644 index 00000000000..c6a19ec13ab Binary files /dev/null and b/Resources/Textures/DeltaV/Mobs/Animals/shrimp.rsi/shrimp.png differ