Merge remote-tracking branch 'upstream/master' into upstream-sync
# Conflicts: # Resources/Prototypes/Datasets/Names/skeleton_first.yml
|
|
@ -34,7 +34,7 @@ public sealed class BackgroundAudioSystem : EntitySystem
|
|||
|
||||
_client.PlayerLeaveServer += OnLeave;
|
||||
|
||||
_gameTicker.LobbyStatusUpdated += LobbySongReceived;
|
||||
_gameTicker.LobbySongUpdated += LobbySongUpdated;
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
|
|
@ -48,7 +48,7 @@ public sealed class BackgroundAudioSystem : EntitySystem
|
|||
|
||||
_client.PlayerLeaveServer -= OnLeave;
|
||||
|
||||
_gameTicker.LobbyStatusUpdated -= LobbySongReceived;
|
||||
_gameTicker.LobbySongUpdated -= LobbySongUpdated;
|
||||
|
||||
EndLobbyMusic();
|
||||
}
|
||||
|
|
@ -95,17 +95,9 @@ public sealed class BackgroundAudioSystem : EntitySystem
|
|||
}
|
||||
}
|
||||
|
||||
private void LobbySongReceived()
|
||||
private void LobbySongUpdated()
|
||||
{
|
||||
if (_lobbyStream != null) //Toggling Ready status fires this method. This check ensures we only start the lobby music if it's not playing.
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_stateManager.CurrentState is LobbyState)
|
||||
{
|
||||
StartLobbyMusic();
|
||||
}
|
||||
RestartLobbyMusic();
|
||||
}
|
||||
|
||||
public void RestartLobbyMusic()
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ using Content.Shared.Eye.Blinding.Components;
|
|||
using Robust.Client;
|
||||
using static Content.Shared.Interaction.SharedInteractionSystem;
|
||||
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Item;
|
||||
|
||||
namespace Content.Client.Examine
|
||||
{
|
||||
|
|
@ -50,6 +52,8 @@ namespace Content.Client.Examine
|
|||
|
||||
SubscribeNetworkEvent<ExamineSystemMessages.ExamineInfoResponseMessage>(OnExamineInfoResponse);
|
||||
|
||||
SubscribeLocalEvent<ItemComponent, DroppedEvent>(OnExaminedItemDropped);
|
||||
|
||||
CommandBinds.Builder
|
||||
.Bind(ContentKeyFunctions.ExamineEntity, new PointerInputCmdHandler(HandleExamine, outsidePrediction: true))
|
||||
.Register<ExamineSystem>();
|
||||
|
|
@ -57,6 +61,19 @@ namespace Content.Client.Examine
|
|||
_idCounter = 0;
|
||||
}
|
||||
|
||||
private void OnExaminedItemDropped(EntityUid item, ItemComponent comp, DroppedEvent args)
|
||||
{
|
||||
if (!args.User.Valid)
|
||||
return;
|
||||
if (_playerManager.LocalPlayer == null)
|
||||
return;
|
||||
if (_examineTooltipOpen == null)
|
||||
return;
|
||||
|
||||
if (item == _examinedEntity && args.User == _playerManager.LocalPlayer.ControlledEntity)
|
||||
CloseTooltip();
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
if (_examineTooltipOpen is not {Visible: true}) return;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
using Content.Client.Audio;
|
||||
using Content.Client.Gameplay;
|
||||
using Content.Client.Lobby;
|
||||
using Content.Client.RoundEnd;
|
||||
|
|
@ -8,7 +7,6 @@ using Content.Shared.GameWindow;
|
|||
using JetBrains.Annotations;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.State;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Utility;
|
||||
|
|
@ -21,7 +19,6 @@ namespace Content.Client.GameTicking.Managers
|
|||
[Dependency] private readonly IStateManager _stateManager = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IConfigurationManager _configManager = default!;
|
||||
[Dependency] private readonly BackgroundAudioSystem _backgroundAudio = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
|
||||
[ViewVariables] private bool _initialized;
|
||||
|
|
@ -49,6 +46,7 @@ namespace Content.Client.GameTicking.Managers
|
|||
|
||||
public event Action? InfoBlobUpdated;
|
||||
public event Action? LobbyStatusUpdated;
|
||||
public event Action? LobbySongUpdated;
|
||||
public event Action? LobbyLateJoinStatusUpdated;
|
||||
public event Action<IReadOnlyDictionary<EntityUid, Dictionary<string, uint?>>>? LobbyJobsAvailableUpdated;
|
||||
|
||||
|
|
@ -73,6 +71,16 @@ namespace Content.Client.GameTicking.Managers
|
|||
_initialized = true;
|
||||
}
|
||||
|
||||
public void SetLobbySong(string? song, bool forceUpdate = false)
|
||||
{
|
||||
var updated = song != LobbySong;
|
||||
|
||||
LobbySong = song;
|
||||
|
||||
if (updated || forceUpdate)
|
||||
LobbySongUpdated?.Invoke();
|
||||
}
|
||||
|
||||
private void LateJoinStatus(TickerLateJoinStatusEvent message)
|
||||
{
|
||||
DisallowedLateJoin = message.Disallowed;
|
||||
|
|
@ -97,7 +105,7 @@ namespace Content.Client.GameTicking.Managers
|
|||
RoundStartTimeSpan = message.RoundStartTimeSpan;
|
||||
IsGameStarted = message.IsRoundStarted;
|
||||
AreWeReady = message.YouAreReady;
|
||||
LobbySong = message.LobbySong;
|
||||
SetLobbySong(message.LobbySong);
|
||||
LobbyBackground = message.LobbyBackground;
|
||||
Paused = message.Paused;
|
||||
|
||||
|
|
@ -124,12 +132,8 @@ namespace Content.Client.GameTicking.Managers
|
|||
|
||||
private void RoundEnd(RoundEndMessageEvent message)
|
||||
{
|
||||
if (message.LobbySong != null)
|
||||
{
|
||||
LobbySong = message.LobbySong;
|
||||
_backgroundAudio.StartLobbyMusic();
|
||||
}
|
||||
|
||||
// Force an update in the event of this song being the same as the last.
|
||||
SetLobbySong(message.LobbySong, true);
|
||||
RestartSound = message.RestartSound;
|
||||
|
||||
// Don't open duplicate windows (mainly for replays).
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ public sealed class StealthSystem : SharedStealthSystem
|
|||
|
||||
if (!enabled)
|
||||
{
|
||||
if (component.HadOutline)
|
||||
if (component.HadOutline && !TerminatingOrDeleted(uid))
|
||||
EnsureComp<InteractionOutlineComponent>(uid);
|
||||
return;
|
||||
}
|
||||
|
|
@ -63,7 +63,8 @@ public sealed class StealthSystem : SharedStealthSystem
|
|||
|
||||
private void OnShutdown(EntityUid uid, StealthComponent component, ComponentShutdown args)
|
||||
{
|
||||
SetShader(uid, false, component);
|
||||
if (!Terminating(uid))
|
||||
SetShader(uid, false, component);
|
||||
}
|
||||
|
||||
private void OnShaderRender(EntityUid uid, StealthComponent component, BeforePostShaderRenderEvent args)
|
||||
|
|
|
|||
|
|
@ -153,17 +153,10 @@ namespace Content.IntegrationTests.Tests
|
|||
.Select(p => p.ID)
|
||||
.ToList();
|
||||
|
||||
// for whatever reason, stealth boxes are breaking this test. Surplus crates have a chance of spawning them.
|
||||
// TODO fix whatever is going wrong here.
|
||||
HashSet<string> ignored = new() { "GhostBox", "StealthBox", "CrateSyndicateSurplusBundle", "CrateSyndicateSuperSurplusBundle" };
|
||||
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
foreach (var protoId in protoIds)
|
||||
{
|
||||
if (ignored.Contains(protoId))
|
||||
continue;
|
||||
|
||||
var mapId = mapManager.CreateMap();
|
||||
var grid = mapManager.CreateGrid(mapId);
|
||||
var ent = sEntMan.SpawnEntity(protoId, new EntityCoordinates(grid.Owner, 0.5f, 0.5f));
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ public sealed partial class MindTests
|
|||
[Test]
|
||||
public async Task TestGhostOnDeleteMap()
|
||||
{
|
||||
await using var pairTracker = await SetupPair();
|
||||
await using var pairTracker = await SetupPair(dirty: true);
|
||||
var server = pairTracker.Pair.Server;
|
||||
var testMap = await PoolManager.CreateTestMap(pairTracker);
|
||||
var coordinates = testMap.GridCoords;
|
||||
|
|
|
|||
|
|
@ -29,18 +29,9 @@ namespace Content.IntegrationTests.Tests;
|
|||
[TestFixture]
|
||||
public sealed class PrototypeSaveTest
|
||||
{
|
||||
private readonly HashSet<string> _ignoredPrototypes = new()
|
||||
{
|
||||
"Singularity", // physics collision uses "AllMask" (-1). The flag serializer currently fails to save this because this features un-named bits.
|
||||
"constructionghost",
|
||||
// Don't add to this list unless you have a good reason
|
||||
// Or it is just temporary because tests stopped working and now master has too many broken entities.
|
||||
};
|
||||
|
||||
[Test]
|
||||
public async Task UninitializedSaveTest()
|
||||
{
|
||||
// Apparently SpawnTest fails to clean up properly. Due to the similarities, I'll assume this also fails.
|
||||
await using var pairTracker = await PoolManager.GetServerClient();
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
|
|
@ -92,9 +83,6 @@ public sealed class PrototypeSaveTest
|
|||
if (!prototype.MapSavable)
|
||||
continue;
|
||||
|
||||
if (_ignoredPrototypes.Contains(prototype.ID))
|
||||
continue;
|
||||
|
||||
if (prototype.SetSuffix == "DEBUG")
|
||||
continue;
|
||||
|
||||
|
|
@ -165,10 +153,7 @@ public sealed class PrototypeSaveTest
|
|||
var diff = compMapping.Except(protoMapping);
|
||||
|
||||
if (diff != null && diff.Children.Count != 0)
|
||||
{
|
||||
var modComps = string.Join(",", diff.Keys.Select(x => x.ToString()));
|
||||
Assert.Fail($"Prototype {prototype.ID} modifies component on spawn: {compName}. Modified fields: {modComps}");
|
||||
}
|
||||
Assert.Fail($"Prototype {prototype.ID} modifies component on spawn: {compName}. Modified yaml:\n{diff}");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
using Content.Server.DeviceLinking.Components;
|
||||
using Content.Shared.Atmos.Monitor;
|
||||
using Content.Shared.Atmos.Monitor.Components;
|
||||
using Content.Shared.Atmos.Piping.Unary.Components;
|
||||
using Content.Shared.DeviceLinking;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
|
||||
namespace Content.Server.Atmos.Monitor.Components;
|
||||
|
||||
|
|
@ -24,4 +27,28 @@ public sealed class AirAlarmComponent : Component
|
|||
public HashSet<NetUserId> ActivePlayers = new();
|
||||
|
||||
public bool CanSync = true;
|
||||
|
||||
/// <summary>
|
||||
/// Previous alarm state for use with output ports.
|
||||
/// </summary>
|
||||
[DataField("state")]
|
||||
public AtmosAlarmType State = AtmosAlarmType.Normal;
|
||||
|
||||
/// <summary>
|
||||
/// The port that gets set to high while the alarm is in the danger state, and low when not.
|
||||
/// </summary>
|
||||
[DataField("dangerPort", customTypeSerializer: typeof(PrototypeIdSerializer<SourcePortPrototype>))]
|
||||
public string DangerPort = "AirDanger";
|
||||
|
||||
/// <summary>
|
||||
/// The port that gets set to high while the alarm is in the warning state, and low when not.
|
||||
/// </summary>
|
||||
[DataField("warningPort", customTypeSerializer: typeof(PrototypeIdSerializer<SourcePortPrototype>))]
|
||||
public string WarningPort = "AirWarning";
|
||||
|
||||
/// <summary>
|
||||
/// The port that gets set to high while the alarm is in the normal state, and low when not.
|
||||
/// </summary>
|
||||
[DataField("normalPort", customTypeSerializer: typeof(PrototypeIdSerializer<SourcePortPrototype>))]
|
||||
public string NormalPort = "AirNormal";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using System.Linq;
|
||||
using Content.Server.Atmos.Monitor.Components;
|
||||
using Content.Server.Atmos.Piping.Components;
|
||||
using Content.Server.DeviceLinking.Systems;
|
||||
using Content.Server.DeviceNetwork;
|
||||
using Content.Server.DeviceNetwork.Components;
|
||||
using Content.Server.DeviceNetwork.Systems;
|
||||
|
|
@ -13,6 +14,7 @@ using Content.Shared.Atmos;
|
|||
using Content.Shared.Atmos.Monitor;
|
||||
using Content.Shared.Atmos.Monitor.Components;
|
||||
using Content.Shared.Atmos.Piping.Unary.Components;
|
||||
using Content.Shared.DeviceLinking;
|
||||
using Content.Shared.DeviceNetwork;
|
||||
using Content.Shared.DeviceNetwork.Systems;
|
||||
using Content.Shared.Interaction;
|
||||
|
|
@ -32,14 +34,14 @@ namespace Content.Server.Atmos.Monitor.Systems;
|
|||
// response data in its data key.
|
||||
public sealed class AirAlarmSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly DeviceNetworkSystem _deviceNet = default!;
|
||||
[Dependency] private readonly DeviceListSystem _deviceListSystem = default!;
|
||||
[Dependency] private readonly AtmosDeviceNetworkSystem _atmosDevNetSystem = default!;
|
||||
[Dependency] private readonly AccessReaderSystem _access = default!;
|
||||
[Dependency] private readonly AtmosAlarmableSystem _atmosAlarmable = default!;
|
||||
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
|
||||
[Dependency] private readonly AccessReaderSystem _accessSystem = default!;
|
||||
[Dependency] private readonly AtmosDeviceNetworkSystem _atmosDevNet = default!;
|
||||
[Dependency] private readonly DeviceNetworkSystem _deviceNet = default!;
|
||||
[Dependency] private readonly DeviceLinkSystem _deviceLink = default!;
|
||||
[Dependency] private readonly DeviceListSystem _deviceList = default!;
|
||||
[Dependency] private readonly PopupSystem _popup = default!;
|
||||
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
|
||||
[Dependency] private readonly UserInterfaceSystem _ui = default!;
|
||||
|
||||
#region Device Network API
|
||||
|
||||
|
|
@ -57,8 +59,8 @@ public sealed class AirAlarmSystem : EntitySystem
|
|||
/// <param name="data">The data to send to the device.</param>
|
||||
public void SetData(EntityUid uid, string address, IAtmosDeviceData data)
|
||||
{
|
||||
_atmosDevNetSystem.SetDeviceState(uid, address, data);
|
||||
_atmosDevNetSystem.Sync(uid, address);
|
||||
_atmosDevNet.SetDeviceState(uid, address, data);
|
||||
_atmosDevNet.Sync(uid, address);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -66,7 +68,7 @@ public sealed class AirAlarmSystem : EntitySystem
|
|||
/// </summary>
|
||||
private void SyncAllDevices(EntityUid uid)
|
||||
{
|
||||
_atmosDevNetSystem.Sync(uid, null);
|
||||
_atmosDevNet.Sync(uid, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -75,7 +77,7 @@ public sealed class AirAlarmSystem : EntitySystem
|
|||
/// <param name="address">The address of the device.</param>
|
||||
private void SyncDevice(EntityUid uid, string address)
|
||||
{
|
||||
_atmosDevNetSystem.Sync(uid, address);
|
||||
_atmosDevNet.Sync(uid, address);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -85,8 +87,8 @@ public sealed class AirAlarmSystem : EntitySystem
|
|||
/// <param name="uid"></param>
|
||||
private void SyncRegisterAllDevices(EntityUid uid)
|
||||
{
|
||||
_atmosDevNetSystem.Register(uid, null);
|
||||
_atmosDevNetSystem.Sync(uid, null);
|
||||
_atmosDevNet.Register(uid, null);
|
||||
_atmosDevNet.Sync(uid, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -133,8 +135,7 @@ public sealed class AirAlarmSystem : EntitySystem
|
|||
/// <param name="mode">The mode to sync with the rest of the network.</param>
|
||||
private void SyncMode(EntityUid uid, AirAlarmMode mode)
|
||||
{
|
||||
if (EntityManager.TryGetComponent(uid, out AtmosMonitorComponent? monitor)
|
||||
&& !monitor.NetEnabled)
|
||||
if (TryComp<AtmosMonitorComponent>(uid, out var monitor) && !monitor.NetEnabled)
|
||||
return;
|
||||
|
||||
var payload = new NetworkPayload
|
||||
|
|
@ -165,6 +166,8 @@ public sealed class AirAlarmSystem : EntitySystem
|
|||
SubscribeLocalEvent<AirAlarmComponent, AirAlarmTabSetMessage>(OnTabChange);
|
||||
SubscribeLocalEvent<AirAlarmComponent, DeviceListUpdateEvent>(OnDeviceListUpdate);
|
||||
SubscribeLocalEvent<AirAlarmComponent, BoundUIClosedEvent>(OnClose);
|
||||
SubscribeLocalEvent<AirAlarmComponent, ComponentInit>(OnInit);
|
||||
SubscribeLocalEvent<AirAlarmComponent, MapInitEvent>(OnMapInit);
|
||||
SubscribeLocalEvent<AirAlarmComponent, ComponentShutdown>(OnShutdown);
|
||||
SubscribeLocalEvent<AirAlarmComponent, ActivateInWorldEvent>(OnActivate);
|
||||
}
|
||||
|
|
@ -179,7 +182,7 @@ public sealed class AirAlarmSystem : EntitySystem
|
|||
continue;
|
||||
}
|
||||
|
||||
_atmosDevNetSystem.Deregister(uid, deviceNet.Address);
|
||||
_atmosDevNet.Deregister(uid, deviceNet.Address);
|
||||
}
|
||||
|
||||
component.ScrubberData.Clear();
|
||||
|
|
@ -220,6 +223,18 @@ public sealed class AirAlarmSystem : EntitySystem
|
|||
RemoveActiveInterface(uid);
|
||||
}
|
||||
|
||||
private void OnInit(EntityUid uid, AirAlarmComponent comp, ComponentInit args)
|
||||
{
|
||||
_deviceLink.EnsureSourcePorts(uid, comp.DangerPort, comp.WarningPort, comp.NormalPort);
|
||||
}
|
||||
|
||||
private void OnMapInit(EntityUid uid, AirAlarmComponent comp, MapInitEvent args)
|
||||
{
|
||||
// for mapped linked air alarms, start with high so when it changes for the first time it goes from high to low
|
||||
// without this the output would suddenly get sent a low signal after nothing which is bad
|
||||
_deviceLink.SendSignal(uid, GetPort(comp), true);
|
||||
}
|
||||
|
||||
private void OnShutdown(EntityUid uid, AirAlarmComponent component, ComponentShutdown args)
|
||||
{
|
||||
_activeUserInterfaces.Remove(uid);
|
||||
|
|
@ -227,9 +242,6 @@ public sealed class AirAlarmSystem : EntitySystem
|
|||
|
||||
private void OnActivate(EntityUid uid, AirAlarmComponent component, ActivateInWorldEvent args)
|
||||
{
|
||||
if (!_interactionSystem.InRangeUnobstructed(args.User, args.Target))
|
||||
return;
|
||||
|
||||
if (!TryComp<ActorComponent>(args.User, out var actor))
|
||||
return;
|
||||
|
||||
|
|
@ -242,9 +254,9 @@ public sealed class AirAlarmSystem : EntitySystem
|
|||
if (!this.IsPowered(uid, EntityManager))
|
||||
return;
|
||||
|
||||
var ui = _uiSystem.GetUiOrNull(uid, SharedAirAlarmInterfaceKey.Key);
|
||||
var ui = _ui.GetUiOrNull(uid, SharedAirAlarmInterfaceKey.Key);
|
||||
if (ui != null)
|
||||
_uiSystem.OpenUi(ui, actor.PlayerSession);
|
||||
_ui.OpenUi(ui, actor.PlayerSession);
|
||||
component.ActivePlayers.Add(actor.PlayerSession.UserId);
|
||||
AddActiveInterface(uid);
|
||||
SyncAllDevices(uid);
|
||||
|
|
@ -268,12 +280,20 @@ public sealed class AirAlarmSystem : EntitySystem
|
|||
|
||||
private void OnUpdateAlarmMode(EntityUid uid, AirAlarmComponent component, AirAlarmUpdateAlarmModeMessage args)
|
||||
{
|
||||
var addr = string.Empty;
|
||||
if (EntityManager.TryGetComponent(uid, out DeviceNetworkComponent? netConn)) addr = netConn.Address;
|
||||
if (AccessCheck(uid, args.Session.AttachedEntity, component))
|
||||
{
|
||||
var addr = string.Empty;
|
||||
if (TryComp<DeviceNetworkComponent>(uid, out var netConn))
|
||||
{
|
||||
addr = netConn.Address;
|
||||
}
|
||||
|
||||
SetMode(uid, addr, args.Mode, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateUI(uid, component);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnUpdateAutoMode(EntityUid uid, AirAlarmComponent component, AirAlarmUpdateAutoModeMessage args)
|
||||
|
|
@ -293,7 +313,7 @@ public sealed class AirAlarmSystem : EntitySystem
|
|||
private void OnUpdateDeviceData(EntityUid uid, AirAlarmComponent component, AirAlarmUpdateDeviceDataMessage args)
|
||||
{
|
||||
if (AccessCheck(uid, args.Session.AttachedEntity, component)
|
||||
&& _deviceListSystem.ExistsInDeviceList(uid, args.Address))
|
||||
&& _deviceList.ExistsInDeviceList(uid, args.Address))
|
||||
{
|
||||
SetDeviceData(uid, args.Address, args.Data);
|
||||
}
|
||||
|
|
@ -334,10 +354,14 @@ public sealed class AirAlarmSystem : EntitySystem
|
|||
if (!Resolve(uid, ref component))
|
||||
return false;
|
||||
|
||||
if (!EntityManager.TryGetComponent(uid, out AccessReaderComponent? reader) || user == null)
|
||||
// if it has no access reader behave as if the user has AA
|
||||
if (!TryComp<AccessReaderComponent>(uid, out var reader))
|
||||
return true;
|
||||
|
||||
if (user == null)
|
||||
return false;
|
||||
|
||||
if (!_accessSystem.IsAllowed(user.Value, reader))
|
||||
if (!_access.IsAllowed(user.Value, reader))
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("air-alarm-ui-access-denied"), user.Value, user.Value);
|
||||
return false;
|
||||
|
|
@ -354,8 +378,10 @@ public sealed class AirAlarmSystem : EntitySystem
|
|||
}
|
||||
|
||||
var addr = string.Empty;
|
||||
if (EntityManager.TryGetComponent(uid, out DeviceNetworkComponent? netConn))
|
||||
if (TryComp<DeviceNetworkComponent>(uid, out var netConn))
|
||||
{
|
||||
addr = netConn.Address;
|
||||
}
|
||||
|
||||
if (component.AutoMode)
|
||||
{
|
||||
|
|
@ -369,9 +395,32 @@ public sealed class AirAlarmSystem : EntitySystem
|
|||
}
|
||||
}
|
||||
|
||||
if (component.State != args.AlarmType)
|
||||
{
|
||||
TryComp<DeviceLinkSourceComponent>(uid, out var source);
|
||||
|
||||
// send low to old state's port
|
||||
_deviceLink.SendSignal(uid, GetPort(component), false, source);
|
||||
|
||||
// send high to new state's port, along with updating the cached state
|
||||
component.State = args.AlarmType;
|
||||
_deviceLink.SendSignal(uid, GetPort(component), true, source);
|
||||
}
|
||||
|
||||
UpdateUI(uid, component);
|
||||
}
|
||||
|
||||
private string GetPort(AirAlarmComponent comp)
|
||||
{
|
||||
if (comp.State == AtmosAlarmType.Danger)
|
||||
return comp.DangerPort;
|
||||
|
||||
if (comp.State == AtmosAlarmType.Warning)
|
||||
return comp.WarningPort;
|
||||
|
||||
return comp.NormalPort;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Air Alarm Settings
|
||||
|
|
@ -517,7 +566,7 @@ public sealed class AirAlarmSystem : EntitySystem
|
|||
/// </summary>
|
||||
private void ForceCloseAllInterfaces(EntityUid uid)
|
||||
{
|
||||
_uiSystem.TryCloseAll(uid, SharedAirAlarmInterfaceKey.Key);
|
||||
_ui.TryCloseAll(uid, SharedAirAlarmInterfaceKey.Key);
|
||||
}
|
||||
|
||||
private void OnAtmosUpdate(EntityUid uid, AirAlarmComponent alarm, AtmosDeviceUpdateEvent args)
|
||||
|
|
@ -585,7 +634,7 @@ public sealed class AirAlarmSystem : EntitySystem
|
|||
highestAlarm = AtmosAlarmType.Normal;
|
||||
}
|
||||
|
||||
_uiSystem.TrySetUiState(
|
||||
_ui.TrySetUiState(
|
||||
uid,
|
||||
SharedAirAlarmInterfaceKey.Key,
|
||||
new AirAlarmUIState(devNet.Address, deviceCount, pressure, temperature, dataToSend, alarm.CurrentMode, alarm.CurrentTab, highestAlarm.Value, alarm.AutoMode));
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Content.Server.Administration.Logs;
|
||||
|
|
@ -201,8 +202,11 @@ public sealed partial class ChatSystem : SharedChatSystem
|
|||
|
||||
bool shouldCapitalize = (desiredType != InGameICChatType.Emote);
|
||||
bool shouldPunctuate = _configurationManager.GetCVar(CCVars.ChatPunctuation);
|
||||
// Capitalizing the word I only happens in English, so we check language here
|
||||
bool shouldCapitalizeTheWordI = (!CultureInfo.CurrentCulture.IsNeutralCulture && CultureInfo.CurrentCulture.Parent.Name == "en")
|
||||
|| (CultureInfo.CurrentCulture.IsNeutralCulture && CultureInfo.CurrentCulture.Name == "en");
|
||||
|
||||
message = SanitizeInGameICMessage(source, message, out var emoteStr, shouldCapitalize, shouldPunctuate);
|
||||
message = SanitizeInGameICMessage(source, message, out var emoteStr, shouldCapitalize, shouldPunctuate, shouldCapitalizeTheWordI);
|
||||
|
||||
// Was there an emote in the message? If so, send it.
|
||||
if (player != null && emoteStr != message && emoteStr != null)
|
||||
|
|
@ -687,12 +691,14 @@ public sealed partial class ChatSystem : SharedChatSystem
|
|||
}
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
private string SanitizeInGameICMessage(EntityUid source, string message, out string? emoteStr, bool capitalize = true, bool punctuate = false)
|
||||
private string SanitizeInGameICMessage(EntityUid source, string message, out string? emoteStr, bool capitalize = true, bool punctuate = false, bool capitalizeTheWordI = true)
|
||||
{
|
||||
var newMessage = message.Trim();
|
||||
newMessage = ReplaceWords(newMessage); // Corvax-ChatSanitize
|
||||
if (capitalize)
|
||||
newMessage = SanitizeMessageCapital(newMessage);
|
||||
if (capitalizeTheWordI)
|
||||
newMessage = SanitizeMessageCapitalizeTheWordI(newMessage, "i");
|
||||
if (punctuate)
|
||||
newMessage = SanitizeMessagePeriod(newMessage);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using Content.Server.DeviceLinking.Components;
|
||||
using Content.Server.DeviceLinking.Events;
|
||||
using Content.Server.DeviceNetwork;
|
||||
using Content.Server.DeviceNetwork.Components;
|
||||
|
|
@ -95,11 +96,25 @@ public sealed class DeviceLinkSystem : SharedDeviceLinkSystem
|
|||
}
|
||||
}
|
||||
|
||||
_deviceNetworkSystem.QueuePacket(uid, sinkNetworkComponent.Address, payload, sinkNetworkComponent.ReceiveFrequency);
|
||||
// force using wireless network so things like atmos devices are able to send signals
|
||||
var network = (int) DeviceNetworkComponent.DeviceNetIdDefaults.Wireless;
|
||||
_deviceNetworkSystem.QueuePacket(uid, sinkNetworkComponent.Address, payload, sinkNetworkComponent.ReceiveFrequency, network);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper function that invokes a port with a high/low binary logic signal.
|
||||
/// </summary>
|
||||
public void SendSignal(EntityUid uid, string port, bool signal, DeviceLinkSourceComponent? comp = null)
|
||||
{
|
||||
var data = new NetworkPayload
|
||||
{
|
||||
[DeviceNetworkConstants.LogicState] = signal ? SignalState.High : SignalState.Low
|
||||
};
|
||||
InvokePort(uid, port, data, comp);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the payload has a port defined and if the port is present on the sink.
|
||||
/// Raises a <see cref="SignalReceivedEvent"/> containing the payload when the check passes
|
||||
|
|
|
|||
|
|
@ -140,12 +140,7 @@ public sealed class LogicGateSystem : EntitySystem
|
|||
{
|
||||
comp.LastOutput = output;
|
||||
|
||||
var data = new NetworkPayload
|
||||
{
|
||||
[DeviceNetworkConstants.LogicState] = output ? SignalState.High : SignalState.Low
|
||||
};
|
||||
|
||||
_deviceLink.InvokePort(uid, comp.OutputPort, data);
|
||||
_deviceLink.SendSignal(uid, comp.OutputPort, output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,15 +30,11 @@ public sealed class SignalSwitchSystem : EntitySystem
|
|||
|
||||
comp.State = !comp.State;
|
||||
_deviceLink.InvokePort(uid, comp.State ? comp.OnPort : comp.OffPort);
|
||||
var data = new NetworkPayload
|
||||
{
|
||||
[DeviceNetworkConstants.LogicState] = comp.State ? SignalState.High : SignalState.Low
|
||||
};
|
||||
|
||||
// only send status if it's a toggle switch and not a button
|
||||
if (comp.OnPort != comp.OffPort)
|
||||
{
|
||||
_deviceLink.InvokePort(uid, comp.StatusPort, data);
|
||||
_deviceLink.SendSignal(uid, comp.StatusPort, comp.State);
|
||||
}
|
||||
|
||||
_audio.PlayPvs(comp.ClickSound, uid, AudioParams.Default.WithVariation(0.125f).WithVolume(8f));
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ namespace Content.Server.DeviceNetwork.Systems
|
|||
/// <param name="frequency">The frequency to send on</param>
|
||||
/// <param name="data">The data to be sent</param>
|
||||
/// <returns>Returns true when the packet was successfully enqueued.</returns>
|
||||
public bool QueuePacket(EntityUid uid, string? address, NetworkPayload data, uint? frequency = null, DeviceNetworkComponent? device = null)
|
||||
public bool QueuePacket(EntityUid uid, string? address, NetworkPayload data, uint? frequency = null, int? network = null, DeviceNetworkComponent? device = null)
|
||||
{
|
||||
if (!Resolve(uid, ref device, false))
|
||||
return false;
|
||||
|
|
@ -79,7 +79,9 @@ namespace Content.Server.DeviceNetwork.Systems
|
|||
if (frequency == null)
|
||||
return false;
|
||||
|
||||
_nextQueue.Enqueue(new DeviceNetworkPacketEvent(device.DeviceNetId, address, frequency.Value, device.Address, uid, data));
|
||||
network ??= device.DeviceNetId;
|
||||
|
||||
_nextQueue.Enqueue(new DeviceNetworkPacketEvent(network.Value, address, frequency.Value, device.Address, uid, data));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ namespace Content.Server.DeviceNetwork.Systems
|
|||
/// </summary>
|
||||
private void OnBeforePacketSent(EntityUid uid, WiredNetworkComponent component, BeforePacketSentEvent args)
|
||||
{
|
||||
if (EntityManager.GetComponent<TransformComponent>(uid).GridUid != args.SenderTransform.GridUid)
|
||||
if (Transform(uid).GridUid != args.SenderTransform.GridUid)
|
||||
{
|
||||
args.Cancel();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,8 +20,11 @@ namespace Content.Server.DeviceNetwork.Systems
|
|||
var ownPosition = args.SenderPosition;
|
||||
var xform = Transform(uid);
|
||||
|
||||
// not a wireless to wireless connection, just let it happen
|
||||
if (!TryComp<WirelessNetworkComponent>(args.Sender, out var sendingComponent))
|
||||
return;
|
||||
|
||||
if (xform.MapID != args.SenderTransform.MapID
|
||||
|| !TryComp<WirelessNetworkComponent>(args.Sender, out var sendingComponent)
|
||||
|| (ownPosition - xform.WorldPosition).Length() > sendingComponent.Range)
|
||||
{
|
||||
args.Cancel();
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ public sealed class MailingUnitSystem : EntitySystem
|
|||
[NetTarget] = component.Target
|
||||
};
|
||||
|
||||
_deviceNetworkSystem.QueuePacket(uid, null, payload, null, device);
|
||||
_deviceNetworkSystem.QueuePacket(uid, null, payload, null, null, device);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -129,7 +129,7 @@ public sealed class MailingUnitSystem : EntitySystem
|
|||
};
|
||||
|
||||
component.TargetList.Clear();
|
||||
_deviceNetworkSystem.QueuePacket(uid, null, payload, null, device);
|
||||
_deviceNetworkSystem.QueuePacket(uid, null, payload, null, null, device);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ using Content.Shared.GameTicking;
|
|||
using Content.Shared.Preferences;
|
||||
using JetBrains.Annotations;
|
||||
using Prometheus;
|
||||
using Robust.Server.GameStates;
|
||||
using Robust.Server.Maps;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Audio;
|
||||
|
|
@ -46,22 +45,6 @@ namespace Content.Server.GameTicking
|
|||
[ViewVariables]
|
||||
private bool _startingRound;
|
||||
|
||||
/// <summary>
|
||||
/// This is a list of players that are going to appear in the round-end
|
||||
/// crew manifest so their children entities can be collected each update
|
||||
/// and sent to far-away players.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
private HashSet<EntityUid> _expandPvsPlayers = new();
|
||||
|
||||
/// <summary>
|
||||
/// This is the list of the children entities that should be sent to
|
||||
/// all players at the end of the round, to keep distant characters from
|
||||
/// looking naked in the crew manifest.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
private HashSet<EntityUid> _expandPvsEntities = new();
|
||||
|
||||
[ViewVariables]
|
||||
private GameRunLevel _runLevel;
|
||||
|
||||
|
|
@ -81,16 +64,6 @@ namespace Content.Server.GameTicking
|
|||
}
|
||||
}
|
||||
|
||||
private void InitializeRoundFlow()
|
||||
{
|
||||
SubscribeLocalEvent<ExpandPvsEvent>(OnExpandPvs);
|
||||
}
|
||||
|
||||
private void OnEntityDeleted(EntityUid uid)
|
||||
{
|
||||
_expandPvsEntities.Remove(uid);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the round's map is eligible to be updated.
|
||||
/// </summary>
|
||||
|
|
@ -324,17 +297,15 @@ namespace Content.Server.GameTicking
|
|||
|
||||
RunLevel = GameRunLevel.PostRound;
|
||||
|
||||
// The lobby song is set here instead of in RestartRound,
|
||||
// because ShowRoundEndScoreboard triggers the start of the music playing
|
||||
// at the end of a round, and this needs to be set before RestartRound
|
||||
// in order for the lobby song status display to be accurate.
|
||||
LobbySong = _robustRandom.Pick(_lobbyMusicCollection.PickFiles).ToString();
|
||||
|
||||
ShowRoundEndScoreboard(text);
|
||||
}
|
||||
|
||||
private void OnExpandPvs(ref ExpandPvsEvent args)
|
||||
{
|
||||
if (RunLevel != GameRunLevel.PostRound)
|
||||
return;
|
||||
|
||||
args.Entities.AddRange(_expandPvsEntities);
|
||||
}
|
||||
|
||||
public void ShowRoundEndScoreboard(string text = "")
|
||||
{
|
||||
// Log end of round
|
||||
|
|
@ -352,11 +323,6 @@ namespace Content.Server.GameTicking
|
|||
//Get the timespan of the round.
|
||||
var roundDuration = RoundDuration();
|
||||
|
||||
// Should already be empty, but just in case.
|
||||
_expandPvsEntities.Clear();
|
||||
_expandPvsPlayers.Clear();
|
||||
EntityManager.EntityDeleted += OnEntityDeleted;
|
||||
|
||||
//Generate a list of basic player info to display in the end round summary.
|
||||
var listOfPlayerInfo = new List<RoundEndMessageEvent.RoundEndPlayerInfo>();
|
||||
// Grab the great big book of all the Minds, we'll need them for this.
|
||||
|
|
@ -390,8 +356,9 @@ namespace Content.Server.GameTicking
|
|||
else if (mind.CurrentEntity != null && TryName(mind.CurrentEntity.Value, out var icName))
|
||||
playerIcName = icName;
|
||||
|
||||
if (Exists(mind.OriginalOwnedEntity))
|
||||
_expandPvsPlayers.Add(mind.OriginalOwnedEntity.Value);
|
||||
var entity = mind.OriginalOwnedEntity;
|
||||
if (Exists(entity))
|
||||
_pvsOverride.AddGlobalOverride(entity.Value, recursive: true);
|
||||
|
||||
var playerEndRoundInfo = new RoundEndMessageEvent.RoundEndPlayerInfo()
|
||||
{
|
||||
|
|
@ -400,7 +367,7 @@ namespace Content.Server.GameTicking
|
|||
PlayerOOCName = contentPlayerData?.Name ?? "(IMPOSSIBLE: REGISTERED MIND WITH NO OWNER)",
|
||||
// Character name takes precedence over current entity name
|
||||
PlayerICName = playerIcName,
|
||||
PlayerEntityUid = mind.OriginalOwnedEntity,
|
||||
PlayerEntityUid = entity,
|
||||
Role = antag
|
||||
? mind.AllRoles.First(role => role.Antagonist).Name
|
||||
: mind.AllRoles.FirstOrDefault()?.Name ?? Loc.GetString("game-ticker-unknown-role"),
|
||||
|
|
@ -411,20 +378,6 @@ namespace Content.Server.GameTicking
|
|||
listOfPlayerInfo.Add(playerEndRoundInfo);
|
||||
}
|
||||
|
||||
// Recursively collect entities for the crew manifest.
|
||||
void RecursePvsEntities(IEnumerable<EntityUid> entities)
|
||||
{
|
||||
_expandPvsEntities.UnionWith(entities);
|
||||
|
||||
foreach (var entity in entities)
|
||||
{
|
||||
if (TryComp<TransformComponent>(entity, out var xform))
|
||||
RecursePvsEntities(xform.ChildEntities);
|
||||
}
|
||||
}
|
||||
|
||||
RecursePvsEntities(_expandPvsPlayers);
|
||||
|
||||
// This ordering mechanism isn't great (no ordering of minds) but functions
|
||||
var listOfPlayerInfoFinal = listOfPlayerInfo.OrderBy(pi => pi.PlayerOOCName).ToArray();
|
||||
|
||||
|
|
@ -455,7 +408,6 @@ namespace Content.Server.GameTicking
|
|||
PlayersJoinedRoundNormally = 0;
|
||||
|
||||
RunLevel = GameRunLevel.PreRoundLobby;
|
||||
LobbySong = _robustRandom.Pick(_lobbyMusicCollection.PickFiles).ToString();
|
||||
RandomizeLobbyBackground();
|
||||
ResettingCleanup();
|
||||
IncrementRoundNumber();
|
||||
|
|
@ -524,10 +476,6 @@ namespace Content.Server.GameTicking
|
|||
|
||||
_allPreviousGameRules.Clear();
|
||||
|
||||
EntityManager.EntityDeleted -= OnEntityDeleted;
|
||||
_expandPvsPlayers.Clear();
|
||||
_expandPvsEntities.Clear();
|
||||
|
||||
// Round restart cleanup event, so entity systems can reset.
|
||||
var ev = new RoundRestartCleanupEvent();
|
||||
RaiseLocalEvent(ev);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ using Content.Shared.Mobs.Systems;
|
|||
using Content.Shared.Roles;
|
||||
using Robust.Server;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.GameStates;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Console;
|
||||
#if EXCEPTION_TOLERANCE
|
||||
|
|
@ -40,6 +41,7 @@ namespace Content.Server.GameTicking
|
|||
[Dependency] private readonly MindSystem _mind = default!;
|
||||
[Dependency] private readonly MindTrackerSystem _mindTracker = default!;
|
||||
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||
[Dependency] private readonly PvsOverrideSystem _pvsOverride = default!;
|
||||
[Dependency] private readonly IAdminLogManager _adminLogs = default!;
|
||||
|
||||
[ViewVariables] private bool _initialized;
|
||||
|
|
@ -70,7 +72,6 @@ namespace Content.Server.GameTicking
|
|||
"Overflow role does not have the correct name!");
|
||||
InitializeGameRules();
|
||||
InitializeReplays();
|
||||
InitializeRoundFlow();
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ using Content.Shared.Popups;
|
|||
using Content.Shared.Toilet;
|
||||
using Content.Shared.Tools;
|
||||
using Content.Shared.Tools.Components;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Random;
|
||||
|
|
@ -37,10 +38,11 @@ namespace Content.Server.Toilet
|
|||
SubscribeLocalEvent<ToiletComponent, ComponentInit>(OnInit);
|
||||
SubscribeLocalEvent<ToiletComponent, MapInitEvent>(OnMapInit);
|
||||
SubscribeLocalEvent<ToiletComponent, InteractUsingEvent>(OnInteractUsing);
|
||||
SubscribeLocalEvent<ToiletComponent, InteractHandEvent>(OnInteractHand, new []{typeof(SharedBuckleSystem)});
|
||||
SubscribeLocalEvent<ToiletComponent, InteractHandEvent>(OnInteractHand);
|
||||
SubscribeLocalEvent<ToiletComponent, ExaminedEvent>(OnExamine);
|
||||
SubscribeLocalEvent<ToiletComponent, SuicideEvent>(OnSuicide);
|
||||
SubscribeLocalEvent<ToiletComponent, ToiletPryDoAfterEvent>(OnToiletPried);
|
||||
SubscribeLocalEvent<ToiletComponent, GetVerbsEvent<AlternativeVerb>>(OnToggleSeatVerb);
|
||||
}
|
||||
|
||||
private void OnSuicide(EntityUid uid, ToiletComponent component, SuicideEvent args)
|
||||
|
|
@ -123,13 +125,26 @@ namespace Content.Server.Toilet
|
|||
}
|
||||
}
|
||||
|
||||
// just want to up/down seat?
|
||||
// check that nobody seats on seat right now
|
||||
if (TryComp<StrapComponent>(uid, out var strap) && strap.BuckledEntities.Count != 0)
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnToggleSeatVerb(EntityUid uid, ToiletComponent component, GetVerbsEvent<AlternativeVerb> args)
|
||||
{
|
||||
if (!args.CanInteract || !args.CanAccess || !CanToggle(uid))
|
||||
return;
|
||||
|
||||
ToggleToiletSeat(uid, component);
|
||||
args.Handled = true;
|
||||
var alterToiletSeatText = component.IsSeatUp ? Loc.GetString("toilet-seat-close") : Loc.GetString("toilet-seat-open");
|
||||
|
||||
var verb = new AlternativeVerb()
|
||||
{
|
||||
Act = () => {
|
||||
if (CanToggle(uid))
|
||||
ToggleToiletSeat(uid, component);
|
||||
},
|
||||
Text = alterToiletSeatText
|
||||
};
|
||||
|
||||
args.Verbs.Add(verb);
|
||||
}
|
||||
|
||||
private void OnExamine(EntityUid uid, ToiletComponent component, ExaminedEvent args)
|
||||
|
|
@ -153,6 +168,11 @@ namespace Content.Server.Toilet
|
|||
UpdateSprite(uid, toilet);
|
||||
}
|
||||
|
||||
public bool CanToggle(EntityUid uid)
|
||||
{
|
||||
return TryComp<StrapComponent>(uid, out var strap) && strap.BuckledEntities.Count == 0;
|
||||
}
|
||||
|
||||
public void ToggleToiletSeat(EntityUid uid, ToiletComponent? component = null)
|
||||
{
|
||||
if (!Resolve(uid, ref component))
|
||||
|
|
|
|||
|
|
@ -162,4 +162,33 @@ public abstract class SharedChatSystem : EntitySystem
|
|||
message = char.ToUpper(message[0]) + message.Remove(0, 1);
|
||||
return message;
|
||||
}
|
||||
|
||||
public string SanitizeMessageCapitalizeTheWordI(string message, string theWordI = "i")
|
||||
{
|
||||
if (string.IsNullOrEmpty(message))
|
||||
return message;
|
||||
|
||||
for
|
||||
(
|
||||
var index = message.IndexOf(theWordI);
|
||||
index != -1;
|
||||
index = message.IndexOf(theWordI, index + 1)
|
||||
)
|
||||
{
|
||||
// Stops the code If It's tryIng to capItalIze the letter I In the mIddle of words
|
||||
// Repeating the code twice is the simplest option
|
||||
if (index + 1 < message.Length && char.IsLetter(message[index + 1]))
|
||||
continue;
|
||||
if (index - 1 >= 0 && char.IsLetter(message[index - 1]))
|
||||
continue;
|
||||
|
||||
var beforeTarget = message.Substring(0, index);
|
||||
var target = message.Substring(index, theWordI.Length);
|
||||
var afterTarget = message.Substring(index + theWordI.Length);
|
||||
|
||||
message = beforeTarget + target.ToUpper() + afterTarget;
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,12 @@ public sealed class StaminaComponent : Component
|
|||
[ViewVariables(VVAccess.ReadWrite), DataField("critThreshold")]
|
||||
public float CritThreshold = 100f;
|
||||
|
||||
/// <summary>
|
||||
/// How long will this mob be stunned for?
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("stunTime")]
|
||||
public TimeSpan StunTime = TimeSpan.FromSeconds(6);
|
||||
|
||||
/// <summary>
|
||||
/// To avoid continuously updating our data we track the last time we updated so we can extrapolate our current stamina.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -394,11 +394,10 @@ public sealed partial class StaminaSystem : EntitySystem
|
|||
component.Critical = true;
|
||||
component.StaminaDamage = component.CritThreshold;
|
||||
|
||||
var stunTime = TimeSpan.FromSeconds(6);
|
||||
_stunSystem.TryParalyze(uid, stunTime, true);
|
||||
_stunSystem.TryParalyze(uid, component.StunTime, true);
|
||||
|
||||
// Give them buffer before being able to be re-stunned
|
||||
component.NextUpdate = _timing.CurTime + stunTime + StamCritBufferTime;
|
||||
component.NextUpdate = _timing.CurTime + component.StunTime + StamCritBufferTime;
|
||||
EnsureComp<ActiveStaminaComponent>(uid);
|
||||
Dirty(component);
|
||||
_adminLogger.Add(LogType.Stamina, LogImpact.Medium, $"{ToPrettyString(uid):user} entered stamina crit");
|
||||
|
|
|
|||
|
|
@ -163,9 +163,9 @@ namespace Content.Shared.Humanoid
|
|||
break;
|
||||
case HumanoidSkinColor.Hues:
|
||||
case HumanoidSkinColor.TintedHues:
|
||||
var rbyte = random.Next(0, 255);
|
||||
var gbyte = random.Next(0, 255);
|
||||
var bbyte = random.Next(0, 255);
|
||||
var rbyte = random.NextByte();
|
||||
var gbyte = random.NextByte();
|
||||
var bbyte = random.NextByte();
|
||||
newSkinColor = new Color(rbyte, gbyte, bbyte);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ public static class SkinColor
|
|||
public static Color TintedHues(Color color)
|
||||
{
|
||||
var newColor = Color.ToHsv(color);
|
||||
newColor.Y = .1f;
|
||||
newColor.Y *= 0.1f;
|
||||
|
||||
return Color.FromHsv(newColor);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.Administration.Logs;
|
||||
using Content.Shared.Audio;
|
||||
|
|
@ -33,6 +34,7 @@ namespace Content.Shared.Weapons.Ranged.Systems;
|
|||
|
||||
public abstract partial class SharedGunSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
|
||||
[Dependency] protected readonly IGameTiming Timing = default!;
|
||||
[Dependency] protected readonly IMapManager MapManager = default!;
|
||||
[Dependency] private readonly INetManager _netManager = default!;
|
||||
|
|
@ -208,7 +210,8 @@ public abstract partial class SharedGunSystem : EntitySystem
|
|||
|
||||
private void AttemptShoot(EntityUid user, EntityUid gunUid, GunComponent gun)
|
||||
{
|
||||
if (gun.FireRate <= 0f)
|
||||
if (gun.FireRate <= 0f ||
|
||||
!_actionBlockerSystem.CanUseHeldEntity(user))
|
||||
return;
|
||||
|
||||
var toCoordinates = gun.ShootCoordinates;
|
||||
|
|
|
|||
|
|
@ -1,67 +1,4 @@
|
|||
Entries:
|
||||
- author: TemporalOroboros
|
||||
changes:
|
||||
- {message: The AME controller increases and decreases in steps of 2 again., type: Tweak}
|
||||
id: 4146
|
||||
time: '2023-06-30T23:24:23.0000000+00:00'
|
||||
- author: Nairodian
|
||||
changes:
|
||||
- {message: MRP rules updated., type: Tweak}
|
||||
id: 4147
|
||||
time: '2023-07-01T00:15:04.0000000+00:00'
|
||||
- author: Lank
|
||||
changes:
|
||||
- {message: 'The Cargo Telepad has been significantly improved, teleporting orders
|
||||
over 4x faster.', type: Tweak}
|
||||
id: 4148
|
||||
time: '2023-07-01T19:00:33.0000000+00:00'
|
||||
- author: Dygon
|
||||
changes:
|
||||
- {message: Windoors can now be bolted through the network system., type: Tweak}
|
||||
id: 4149
|
||||
time: '2023-07-01T19:00:53.0000000+00:00'
|
||||
- author: Dygon
|
||||
changes:
|
||||
- {message: 'Shutters are able to be closed again on windoors, tables, flaps and
|
||||
windows.', type: Fix}
|
||||
id: 4150
|
||||
time: '2023-07-01T19:19:04.0000000+00:00'
|
||||
- author: Slava0135
|
||||
changes:
|
||||
- {message: added rare immovable rod event that can happen late in the game and
|
||||
can literally cut through entire station, type: Add}
|
||||
- {message: immovable rods now move on spawn by default, type: Fix}
|
||||
- {message: you can now warp to immovable rod as ghost, type: Tweak}
|
||||
id: 4151
|
||||
time: '2023-07-02T13:40:07.0000000+00:00'
|
||||
- author: brainfood1183
|
||||
changes:
|
||||
- {message: Fixed Hamlet sprite error on revival., type: Fix}
|
||||
id: 4152
|
||||
time: '2023-07-03T07:59:29.0000000+00:00'
|
||||
- author: HerCoyote23
|
||||
changes:
|
||||
- {message: You can now speak on your department's radio channel using .X, type: Tweak}
|
||||
id: 4153
|
||||
time: '2023-07-03T08:55:08.0000000+00:00'
|
||||
- author: EmoGarbage404
|
||||
changes:
|
||||
- {message: Artifacts now make noises when activated., type: Add}
|
||||
id: 4154
|
||||
time: '2023-07-03T11:14:27.0000000+00:00'
|
||||
- author: noudoit
|
||||
changes:
|
||||
- {message: Attempting to uncuff yourself damages you slightly, type: Tweak}
|
||||
id: 4155
|
||||
time: '2023-07-03T21:30:09.0000000+00:00'
|
||||
- author: dmnct
|
||||
changes:
|
||||
- {message: Added fun!, type: Add}
|
||||
- {message: Removed fun!, type: Remove}
|
||||
- {message: Changed fun!, type: Tweak}
|
||||
- {message: Fixed fun!, type: Fix}
|
||||
id: 4156
|
||||
time: '2023-07-03T21:31:53.0000000+00:00'
|
||||
- author: Geekyhobo
|
||||
changes:
|
||||
- {message: Nukie bundle prices have been adjusted for balance, type: Tweak}
|
||||
|
|
@ -3029,3 +2966,66 @@ Entries:
|
|||
- {message: Changed salvage and QM locker contents, type: Tweak}
|
||||
id: 4645
|
||||
time: '2023-08-21T01:04:43.0000000+00:00'
|
||||
- author: EnDecc
|
||||
changes:
|
||||
- {message: 'Three "plastic crates" in cargo have now been given appropriate labels,
|
||||
after Centcomm forgot to use tape on them. Disaster pizza crate, Softdrinks
|
||||
crate, and Softdrinks bulk crate will now show up in orders appropriately.',
|
||||
type: Fix}
|
||||
id: 4646
|
||||
time: '2023-08-21T18:16:21.0000000+00:00'
|
||||
- author: Errant-4
|
||||
changes:
|
||||
- {message: 'Crit/Dead people that somehow end up holding a gun can no longer fire
|
||||
them. The Gundead aren''t real, they can''t hurt you.', type: Fix}
|
||||
id: 4647
|
||||
time: '2023-08-21T18:27:08.0000000+00:00'
|
||||
- author: Verslebas
|
||||
changes:
|
||||
- {message: Changed admin ghost's hands order, type: Tweak}
|
||||
id: 4648
|
||||
time: '2023-08-21T18:35:30.0000000+00:00'
|
||||
- author: Potato1234_x
|
||||
changes:
|
||||
- {message: Vending machines have been polished. Again., type: Tweak}
|
||||
id: 4649
|
||||
time: '2023-08-21T18:45:54.0000000+00:00'
|
||||
- author: Alekshhh
|
||||
changes:
|
||||
- {message: Changed medical locker contents, type: Tweak}
|
||||
id: 4650
|
||||
time: '2023-08-21T18:49:22.0000000+00:00'
|
||||
- author: deltanedas
|
||||
changes:
|
||||
- {message: Air alarms now have output signal ports for each state., type: Tweak}
|
||||
id: 4651
|
||||
time: '2023-08-21T21:18:30.0000000+00:00'
|
||||
- author: EmoGarbage404
|
||||
changes:
|
||||
- {message: Freshly spawned diona are no longer gray., type: Fix}
|
||||
- {message: Skeletons are no longer extremely saturated in color., type: Fix}
|
||||
id: 4652
|
||||
time: '2023-08-22T02:05:24.0000000+00:00'
|
||||
- author: func_kenobi
|
||||
changes:
|
||||
- {message: "CentComm allowed the station architectors to place Schr\xF6dinger's\
|
||||
\ grilles.", type: Add}
|
||||
id: 4653
|
||||
time: '2023-08-22T02:21:45.0000000+00:00'
|
||||
- author: astriloqua
|
||||
changes:
|
||||
- {message: NanoTransen has hired professionals to teach people how to use toilets.
|
||||
Employees can now properly sit on toilets., type: Tweak}
|
||||
id: 4654
|
||||
time: '2023-08-22T04:21:51.0000000+00:00'
|
||||
- author: kalane15
|
||||
changes:
|
||||
- {message: Dropping item stops its examination, type: Fix}
|
||||
id: 4655
|
||||
time: '2023-08-22T04:28:45.0000000+00:00'
|
||||
- author: Interrobang01
|
||||
changes:
|
||||
- {message: The word "i" is now automatically capitalized in IC chat! Your pinky's
|
||||
structural integrity is now safe!, type: Add}
|
||||
id: 4656
|
||||
time: '2023-08-22T04:43:37.0000000+00:00'
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ signal-port-name-off-transmitter = Off
|
|||
signal-port-description-off-transmitter = This port is invoked whenever the transmitter is turned off.
|
||||
|
||||
signal-port-name-status-transmitter = Status
|
||||
signal-port-description-logic-output = This port is invoked with HIGH or LOW depending on the transmitter status.
|
||||
signal-port-description-status-transmitter = This port is invoked with HIGH or LOW depending on the transmitter status.
|
||||
|
||||
signal-port-name-left = Left
|
||||
signal-port-description-left = This port is invoked whenever the lever is moved to the leftmost position.
|
||||
|
|
@ -36,3 +36,12 @@ signal-port-description-logic-output-high = This port is invoked whenever the in
|
|||
|
||||
signal-port-name-logic-output-low = Low Output
|
||||
signal-port-description-logic-output-low = This port is invoked whenever the input has a falling edge.
|
||||
|
||||
signal-port-name-air-danger = Danger
|
||||
signal-port-description-air-danger = This port is invoked with HIGH when in danger mode and LOW when not.
|
||||
|
||||
signal-port-name-air-warning = Warning
|
||||
signal-port-description-air-warning = This port is invoked with HIGH when in warning mode and LOW when not.
|
||||
|
||||
signal-port-name-air-normal = Normal
|
||||
signal-port-description-air-normal = This port is invoked with HIGH when in normal mode and LOW when not.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
ent-FoodPizza = { ent-CrateFoodPizza }
|
||||
.desc = { ent-CrateFoodPizza.desc }
|
||||
|
||||
ent-FoodPizzaLarge = { ent-CrateFoodPizzaLarge }
|
||||
.desc = { ent-CrateFoodPizzaLarge.desc }
|
||||
|
||||
ent-FoodMRE = { ent-CrateFoodMRE }
|
||||
.desc = { ent-CrateFoodMRE.desc }
|
||||
|
||||
|
|
@ -12,3 +15,9 @@ ent-FoodDinnerware = { ent-CrateFoodDinnerware }
|
|||
|
||||
ent-FoodBarSupply = { ent-CrateFoodBarSupply }
|
||||
.desc = { ent-CrateFoodBarSupply.desc }
|
||||
|
||||
ent-FoodSoftdrinks = { ent-CrateFoodSoftdrinks }
|
||||
.desc = { ent-CrateFoodSoftdrinks.desc }
|
||||
|
||||
ent-FoodSoftdrinksLarge = { ent-CrateFoodSoftdrinksLarge }
|
||||
.desc = { ent-CrateFoodSoftdrinksLarge.desc }
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
ent-CrateFoodPizza = Emergency pizza delivery
|
||||
.desc = Help do your part to end station hunger by distributing pizza to underfunded departments!
|
||||
.desc = Help do your part to end station hunger by distributing pizza to underfunded departments! Includes 4 pizzas.
|
||||
|
||||
ent-CrateFoodPizzaLarge = Disaster pizza delivery
|
||||
.desc = In the ultimate event that all else has failed, Find comfort in that more pizza solves everything. Includes 16 pizzas.
|
||||
|
||||
ent-CrateFoodMRE = MRE crate
|
||||
.desc = A military style meal fit to feed a whole department.
|
||||
|
|
@ -12,3 +15,9 @@ ent-CrateFoodDinnerware = Kitchen dinnerware crate
|
|||
|
||||
ent-CrateFoodBarSupply = Bartending supplies crate
|
||||
.desc = Extra Bar supplies, in case the clown was allowed in the bar unsupervised.
|
||||
|
||||
ent-CrateFoodSoftdrinks = Softdrinks crate
|
||||
.desc = A variety of sodas to complement a small party, without having to empty the soda machines. Includes 14 sodas.
|
||||
|
||||
ent-CrateFoodSoftdrinksLarge = Softdrinks bulk crate
|
||||
.desc = Lots of sodas taken straight out of Centcomm's own vending machines, because you just can't leave your department. Includes 28 sodas.
|
||||
|
|
|
|||
|
|
@ -5,3 +5,5 @@ toilet-component-suicide-head-message-others = {CAPITALIZE(THE($victim))} sticks
|
|||
toilet-component-suicide-head-message = You stick your head into {THE($owner)} and flush it!
|
||||
toilet-component-suicide-message-others = {CAPITALIZE(THE($victim))} bashes themselves with {THE($owner)}!
|
||||
toilet-component-suicide-message = You bash yourself with {THE($owner)}!
|
||||
toilet-seat-close = Close Seat
|
||||
toilet-seat-open = Open Seat
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
torso:
|
||||
part: TorsoHuman
|
||||
connections:
|
||||
- right arm
|
||||
- left arm
|
||||
- right arm
|
||||
right arm:
|
||||
part: RightArmHuman
|
||||
connections:
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
id: FoodPizza
|
||||
icon:
|
||||
sprite: Objects/Consumable/Food/Baked/pizza.rsi
|
||||
state: margherita
|
||||
state: margherita-slice
|
||||
product: CrateFoodPizza
|
||||
cost: 450
|
||||
category: Food
|
||||
|
|
@ -61,7 +61,7 @@
|
|||
- type: cargoProduct
|
||||
id: FoodSoftdrinks
|
||||
icon:
|
||||
sprite: Objects/Consumable/Drinks/beerglass.rsi
|
||||
sprite: Objects/Consumable/Drinks/cola.rsi
|
||||
state: icon
|
||||
product: CrateFoodSoftdrinks
|
||||
cost: 1200
|
||||
|
|
@ -71,7 +71,7 @@
|
|||
- type: cargoProduct
|
||||
id: FoodSoftdrinksLarge
|
||||
icon:
|
||||
sprite: Objects/Consumable/Drinks/beerglass.rsi
|
||||
sprite: Objects/Consumable/Drinks/colabottle.rsi
|
||||
state: icon
|
||||
product: CrateFoodSoftdrinksLarge
|
||||
cost: 2400
|
||||
|
|
|
|||
|
|
@ -14,14 +14,14 @@
|
|||
id: CrateFoodPizzaLarge
|
||||
parent: CratePlastic
|
||||
components:
|
||||
- type: StorageFill
|
||||
contents:
|
||||
- id: FoodBoxPizzaFilled
|
||||
amount: 16
|
||||
- id: KnifePlastic
|
||||
amount: 4
|
||||
- id: LidSalami
|
||||
prob: 0.04
|
||||
- type: StorageFill
|
||||
contents:
|
||||
- id: FoodBoxPizzaFilled
|
||||
amount: 16
|
||||
- id: KnifePlastic
|
||||
amount: 4
|
||||
- id: LidSalami
|
||||
prob: 0.04
|
||||
|
||||
- type: entity
|
||||
id: CrateFoodMRE
|
||||
|
|
@ -109,37 +109,37 @@
|
|||
id: CrateFoodSoftdrinks
|
||||
parent: CratePlastic
|
||||
components:
|
||||
- type: StorageFill
|
||||
contents:
|
||||
- id: DrinkColaCan
|
||||
amount: 4
|
||||
- id: DrinkGrapeCan
|
||||
amount: 2
|
||||
- id: DrinkRootBeerCan
|
||||
amount: 2
|
||||
- id: DrinkIcedTeaCan
|
||||
amount: 2
|
||||
- id: DrinkLemonLimeCan
|
||||
amount: 2
|
||||
- id: DrinkFourteenLokoCan
|
||||
amount: 2
|
||||
- type: StorageFill
|
||||
contents:
|
||||
- id: DrinkColaCan
|
||||
amount: 4
|
||||
- id: DrinkGrapeCan
|
||||
amount: 2
|
||||
- id: DrinkRootBeerCan
|
||||
amount: 2
|
||||
- id: DrinkIcedTeaCan
|
||||
amount: 2
|
||||
- id: DrinkLemonLimeCan
|
||||
amount: 2
|
||||
- id: DrinkFourteenLokoCan
|
||||
amount: 2
|
||||
|
||||
- type: entity
|
||||
id: CrateFoodSoftdrinksLarge
|
||||
parent: CratePlastic
|
||||
components:
|
||||
- type: StorageFill
|
||||
contents:
|
||||
- id: DrinkColaCan
|
||||
amount: 8
|
||||
- id: DrinkGrapeCan
|
||||
amount: 4
|
||||
- id: DrinkRootBeerCan
|
||||
amount: 4
|
||||
- id: DrinkIcedTeaCan
|
||||
amount: 4
|
||||
- id: DrinkLemonLimeCan
|
||||
amount: 4
|
||||
- id: DrinkFourteenLokoCan
|
||||
amount: 4
|
||||
- type: StorageFill
|
||||
contents:
|
||||
- id: DrinkColaCan
|
||||
amount: 8
|
||||
- id: DrinkGrapeCan
|
||||
amount: 4
|
||||
- id: DrinkRootBeerCan
|
||||
amount: 4
|
||||
- id: DrinkIcedTeaCan
|
||||
amount: 4
|
||||
- id: DrinkLemonLimeCan
|
||||
amount: 4
|
||||
- id: DrinkFourteenLokoCan
|
||||
amount: 4
|
||||
|
||||
|
|
|
|||
|
|
@ -187,15 +187,11 @@
|
|||
- id: ClothingMaskSterile
|
||||
- id: ClothingHeadHatBeretCmo
|
||||
- id: ClothingOuterHardsuitMedical
|
||||
- id: DiagnoserMachineCircuitboard
|
||||
- id: VaccinatorMachineCircuitboard
|
||||
- id: Hypospray
|
||||
- id: HandheldCrewMonitor
|
||||
- id: DoorRemoteMedical
|
||||
- id: RubberStampCMO
|
||||
- id: MedicalTechFabCircuitboard
|
||||
- id: MaterialBiomass
|
||||
amount: 3
|
||||
- id: BoxEncryptionKeyMedical
|
||||
|
||||
- type: entity
|
||||
|
|
@ -214,15 +210,11 @@
|
|||
- id: ClothingOuterCoatLabCmo
|
||||
- id: ClothingMaskSterile
|
||||
- id: ClothingHeadHatBeretCmo
|
||||
- id: DiagnoserMachineCircuitboard
|
||||
- id: VaccinatorMachineCircuitboard
|
||||
- id: Hypospray
|
||||
- id: HandheldCrewMonitor
|
||||
- id: DoorRemoteMedical
|
||||
- id: RubberStampCMO
|
||||
- id: MedicalTechFabCircuitboard
|
||||
- id: MaterialBiomass
|
||||
amount: 3
|
||||
- id: BoxEncryptionKeyMedical
|
||||
|
||||
- type: entity
|
||||
|
|
|
|||
|
|
@ -5,16 +5,16 @@
|
|||
components:
|
||||
- type: StorageFill
|
||||
contents:
|
||||
- id: BoxPillCanister
|
||||
- id: BoxSyringe
|
||||
- id: EpinephrineChemistryBottle
|
||||
amount: 3
|
||||
amount: 1
|
||||
- id: Brutepack
|
||||
amount: 2
|
||||
- id: Ointment
|
||||
amount: 2
|
||||
- id: Bloodpack
|
||||
amount: 2
|
||||
- id: Gauze
|
||||
|
||||
- type: entity
|
||||
id: LockerWallMedicalFilled
|
||||
|
|
@ -24,16 +24,16 @@
|
|||
components:
|
||||
- type: StorageFill
|
||||
contents:
|
||||
- id: BoxPillCanister
|
||||
- id: BoxSyringe
|
||||
- id: EpinephrineChemistryBottle
|
||||
amount: 3
|
||||
amount: 1
|
||||
- id: Brutepack
|
||||
amount: 2
|
||||
- id: Ointment
|
||||
amount: 2
|
||||
- id: Bloodpack
|
||||
amount: 2
|
||||
- id: Gauze
|
||||
|
||||
|
||||
- type: entity
|
||||
|
|
@ -67,8 +67,6 @@
|
|||
- id: UniformScrubsColorPurple
|
||||
prob: 0.05
|
||||
orGroup: Surgshrubs
|
||||
- id: NitrousOxideTankFilled
|
||||
prob: 0.3
|
||||
- id: ClothingMaskSterile
|
||||
|
||||
- type: entity
|
||||
|
|
@ -103,8 +101,6 @@
|
|||
- id: UniformScrubsColorPurple
|
||||
prob: 0.05
|
||||
orGroup: Surgshrubs
|
||||
- id: NitrousOxideTankFilled
|
||||
prob: 0.3
|
||||
- id: ClothingMaskSterile
|
||||
|
||||
- type: entity
|
||||
|
|
@ -116,10 +112,17 @@
|
|||
contents:
|
||||
- id: BoxSyringe
|
||||
- id: BoxBeaker
|
||||
- id: BoxBeaker
|
||||
prob: 0.3
|
||||
- id: BoxPillCanister
|
||||
- id: BoxBottle
|
||||
amount: 2
|
||||
|
||||
- id: ChemBag
|
||||
- id: ClothingHandsGlovesLatex
|
||||
- id: ClothingHeadsetMedical
|
||||
- id: ClothingMaskSterile
|
||||
- id: HandLabeler
|
||||
prob: 0.5
|
||||
|
||||
- type: entity
|
||||
id: LockerParamedicFilled
|
||||
suffix: Filled
|
||||
|
|
@ -134,4 +137,8 @@
|
|||
- id: ClothingUniformJumpsuitParamedic
|
||||
- id: ClothingUniformJumpskirtParamedic
|
||||
- id: ClothingEyesHudMedical
|
||||
|
||||
- id: ClothingHandsGlovesLatex
|
||||
- id: ClothingHeadsetMedical
|
||||
- id: ClothingMaskSterile
|
||||
- id: MedkitFilled
|
||||
prob: 0.3
|
||||
|
|
|
|||
|
|
@ -22,3 +22,9 @@
|
|||
- Пателла
|
||||
- Тейлбоун
|
||||
- Бонер
|
||||
- Rib
|
||||
- Hyoid
|
||||
- Coccyx
|
||||
- Tarsus
|
||||
- Lacrimal
|
||||
- Bone
|
||||
|
|
|
|||
|
|
@ -96,3 +96,21 @@
|
|||
name: signal-port-name-logic-output-low
|
||||
description: signal-port-description-logic-output-low
|
||||
defaultLinks: [ Off, Close ]
|
||||
|
||||
- type: sourcePort
|
||||
id: AirDanger
|
||||
name: signal-port-name-air-danger
|
||||
description: signal-port-description-air-danger
|
||||
defaultLinks: [ DoorBolt ]
|
||||
|
||||
- type: sourcePort
|
||||
id: AirWarning
|
||||
name: signal-port-name-air-warning
|
||||
description: signal-port-description-air-warning
|
||||
defaultLinks: [ DoorBolt ]
|
||||
|
||||
- type: sourcePort
|
||||
id: AirNormal
|
||||
name: signal-port-name-air-normal
|
||||
description: signal-port-description-air-normal
|
||||
defaultLinks: [ DoorBolt ]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
- type: entity
|
||||
name: Random Grille Spawner
|
||||
id: GrilleSpawner
|
||||
parent: MarkerBase
|
||||
components:
|
||||
- type: Sprite
|
||||
layers:
|
||||
- sprite: Structures/Walls/random.rsi
|
||||
state: randomgrille
|
||||
- type: RandomSpawner
|
||||
prototypes:
|
||||
- Grille
|
||||
- GrilleBroken
|
||||
chance: 1.0
|
||||
placement:
|
||||
mode: AlignTileAny
|
||||
|
|
@ -17,6 +17,8 @@
|
|||
colliderFixtureId: EventHorizonCollider
|
||||
consumerFixtureId: EventHorizonConsumer
|
||||
- type: GravityWell # To make the singularity attract things.
|
||||
baseRadialAcceleration: 10
|
||||
maxRange: 4
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
EventHorizonCollider:
|
||||
|
|
@ -43,11 +45,16 @@
|
|||
energy: 180
|
||||
level: 1
|
||||
radsPerLevel: 2
|
||||
energyLoss: 1
|
||||
- type: RandomWalk # To make the singularity move around.
|
||||
maxSpeed: 2.5
|
||||
minSpeed: 1.875
|
||||
- type: SingularityDistortion
|
||||
intensity: 20
|
||||
falloffPower: 2.529822
|
||||
intensity: 3645
|
||||
- type: RadiationSource
|
||||
slope: 0.2 # its emit really far away
|
||||
intensity: 2
|
||||
- type: PointLight
|
||||
enabled: true
|
||||
radius: 10
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@
|
|||
- type: Tag
|
||||
tags:
|
||||
- DoorBumpOpener
|
||||
- type: InteractionOutline
|
||||
- type: Construction
|
||||
graph: BaseBigBox
|
||||
node: basebigbox
|
||||
|
|
@ -66,6 +65,7 @@
|
|||
- type: Damageable
|
||||
damageModifierSet: FlimsyMetallic #Syndicate boxes should have a bit of protection
|
||||
- type: Stealth
|
||||
hadOutline: true
|
||||
- type: StealthOnMove
|
||||
passiveVisibilityRate: -0.37
|
||||
movementVisibilityRate: 0.20
|
||||
|
|
@ -74,6 +74,7 @@
|
|||
id: BigBox
|
||||
parent: BaseBigBox
|
||||
components:
|
||||
- type: InteractionOutline
|
||||
- type: Destructible
|
||||
thresholds:
|
||||
- trigger:
|
||||
|
|
|
|||
|
|
@ -2,6 +2,10 @@
|
|||
id: AirAlarm
|
||||
name: air alarm
|
||||
description: An air alarm. Alarms... air?
|
||||
placement:
|
||||
mode: SnapgridCenter
|
||||
snap:
|
||||
- Wallmount
|
||||
components:
|
||||
- type: WallMount
|
||||
- type: ApcPowerReceiver
|
||||
|
|
@ -16,14 +20,22 @@
|
|||
prefix: device-address-prefix-air-alarm
|
||||
sendBroadcastAttemptEvent: true
|
||||
- type: WiredNetworkConnection
|
||||
# for output status ports
|
||||
- type: WirelessNetworkConnection
|
||||
range: 200
|
||||
- type: DeviceList
|
||||
- type: DeviceNetworkRequiresPower
|
||||
- type: DeviceLinkSource
|
||||
ports:
|
||||
- AirDanger
|
||||
- AirWarning
|
||||
- AirNormal
|
||||
- type: AtmosAlarmable
|
||||
syncWith:
|
||||
- AirAlarm
|
||||
- AirSensor
|
||||
- GasVent
|
||||
- GasScrubber
|
||||
- AirAlarm
|
||||
- AirSensor
|
||||
- GasVent
|
||||
- GasScrubber
|
||||
- type: AtmosAlarmableVisuals
|
||||
layerMap: "airAlarmBase"
|
||||
alarmStates:
|
||||
|
|
@ -85,15 +97,15 @@
|
|||
- !type:PlaySoundBehavior
|
||||
sound:
|
||||
path: /Audio/Effects/metalbreak.ogg
|
||||
placement:
|
||||
mode: SnapgridCenter
|
||||
snap:
|
||||
- Wallmount
|
||||
|
||||
- type: entity
|
||||
id: AirAlarmAssembly
|
||||
name: air alarm assembly
|
||||
description: An air alarm. Doesn't look like it'll be alarming air any time soon.
|
||||
placement:
|
||||
mode: SnapgridCenter
|
||||
snap:
|
||||
- Wallmount
|
||||
components:
|
||||
- type: WallMount
|
||||
- type: Clickable
|
||||
|
|
@ -115,7 +127,3 @@
|
|||
node: assembly
|
||||
- type: Transform
|
||||
anchored: true
|
||||
placement:
|
||||
mode: SnapgridCenter
|
||||
snap:
|
||||
- Wallmount
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
roundStart: true
|
||||
prototype: MobDiona
|
||||
sprites: MobDionaSprites
|
||||
defaultSkinTone: "#cdb369"
|
||||
markingLimits: MobDionaMarkingLimits
|
||||
dollPrototype: MobDionaDummy
|
||||
skinColoration: Hues
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
roundStart: false
|
||||
prototype: MobSkeletonPerson
|
||||
sprites: MobSkeletonSprites
|
||||
defaultSkinTone: "#fff9e2"
|
||||
markingLimits: MobHumanMarkingLimits
|
||||
maleFirstNames: skeletonNamesFirst
|
||||
femaleFirstNames: skeletonNamesFirst
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 930 B After Width: | Height: | Size: 534 B |
|
Before Width: | Height: | Size: 1 KiB After Width: | Height: | Size: 452 B |
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"version": 1,
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/1516a728931b4985c1e86f0c5995a5aa1554a1ad and modified by Swept",
|
||||
"copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/1516a728931b4985c1e86f0c5995a5aa1554a1ad and modified by potato1234x (Github) for ss14",
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
|
|
@ -14,22 +14,12 @@
|
|||
"name": "eject-unshaded",
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.4,
|
||||
0.4,
|
||||
0.4,
|
||||
0.4,
|
||||
0.4,
|
||||
0.4,
|
||||
0.4,
|
||||
0.4,
|
||||
0.4,
|
||||
0.4,
|
||||
0.4,
|
||||
0.4,
|
||||
0.4,
|
||||
0.4,
|
||||
0.1
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2
|
||||
]
|
||||
]
|
||||
},
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 555 B After Width: | Height: | Size: 383 B |
|
Before Width: | Height: | Size: 817 B After Width: | Height: | Size: 534 B |
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"version": 1,
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"copyright": "Taken from baystation at https://github.com/Baystation12/Baystation12/commit/f200ae08d71ecbc91412ee650a334981892f5177",
|
||||
"copyright": "Taken from baystation at https://github.com/Baystation12/Baystation12/commit/f200ae08d71ecbc91412ee650a334981892f5177 and modified by potato1234x",
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 498 B After Width: | Height: | Size: 415 B |
|
Before Width: | Height: | Size: 930 B After Width: | Height: | Size: 476 B |
|
Before Width: | Height: | Size: 1.7 KiB |
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"version": 1,
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"copyright": "Taken from baystation at https://github.com/Baystation12/Baystation12/commit/f200ae08d71ecbc91412ee650a334981892f5177",
|
||||
"copyright": "Taken from baystation at https://github.com/Baystation12/Baystation12/commit/f200ae08d71ecbc91412ee650a334981892f5177 and modified by potato1234x (github) for ss14",
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
|
|
@ -23,16 +23,6 @@
|
|||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "hellfire",
|
||||
"delays": [
|
||||
[
|
||||
0.25,
|
||||
0.25,
|
||||
0.25
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "off"
|
||||
},
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 519 B After Width: | Height: | Size: 390 B |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 882 B |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 779 B |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 855 B |
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"version": 1,
|
||||
"license": "CC-BY-SA-4.0",
|
||||
"copyright": "Created by Hyenh#6078 (313846233099927552)",
|
||||
"copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/1516a728931b4985c1e86f0c5995a5aa1554a1ad and modified by potato1234x",
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1 KiB |
|
Before Width: | Height: | Size: 990 B After Width: | Height: | Size: 750 B |
|
Before Width: | Height: | Size: 694 B After Width: | Height: | Size: 244 B |
|
Before Width: | Height: | Size: 516 B After Width: | Height: | Size: 563 B |
|
Before Width: | Height: | Size: 665 B After Width: | Height: | Size: 469 B |
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"version": 1,
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/1516a728931b4985c1e86f0c5995a5aa1554a1ad and modified by Swept",
|
||||
"copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/1516a728931b4985c1e86f0c5995a5aa1554a1ad and modified by Swept and potato1234x",
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 447 B After Width: | Height: | Size: 365 B |
14
Resources/Textures/Structures/Walls/random.rsi/meta.json
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"version": 1,
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"copyright": "Grille sprite taken from https://github.com/tgstation/tgstation at commit 17c603f1d037f22081d446b9a3f3ae8d41f52e86",
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
},
|
||||
"states": [
|
||||
{
|
||||
"name": "randomgrille"
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
Resources/Textures/Structures/Walls/random.rsi/randomgrille.png
Normal file
|
After Width: | Height: | Size: 3 KiB |
|
|
@ -1 +1 @@
|
|||
Subproject commit 8a440d705f753d4cec20e1a3d81b0c5fa77ef726
|
||||
Subproject commit f6c55085fe9a798a45b531c056f5545db1bf4475
|
||||