diff --git a/Content.Client/Animations/TrackUserComponent.cs b/Content.Client/Animations/TrackUserComponent.cs
new file mode 100644
index 0000000000..374c187398
--- /dev/null
+++ b/Content.Client/Animations/TrackUserComponent.cs
@@ -0,0 +1,17 @@
+using System.Numerics;
+
+namespace Content.Client.Animations;
+
+///
+/// Entities with this component tracks the user's world position every frame.
+///
+[RegisterComponent]
+public sealed partial class TrackUserComponent : Component
+{
+ public EntityUid? User;
+
+ ///
+ /// Offset in the direction of the entity's rotation.
+ ///
+ public Vector2 Offset = Vector2.Zero;
+}
diff --git a/Content.Client/Light/EntitySystems/ExpendableLightSystem.cs b/Content.Client/Light/EntitySystems/ExpendableLightSystem.cs
index a2a7fb2531..8077406730 100644
--- a/Content.Client/Light/EntitySystems/ExpendableLightSystem.cs
+++ b/Content.Client/Light/EntitySystems/ExpendableLightSystem.cs
@@ -52,7 +52,7 @@ public sealed class ExpendableLightSystem : VisualizerSystem HorizLinesLookup = new();
- protected Dictionary<(int, Vector2i), (int, Vector2i)> HorizLinesLookupReversed = new();
- protected Dictionary<(int, Vector2i), (int, Vector2i)> VertLinesLookup = new();
- protected Dictionary<(int, Vector2i), (int, Vector2i)> VertLinesLookupReversed = new();
+ private Dictionary _horizLines = new();
+ private Dictionary _horizLinesReversed = new();
+ private Dictionary _vertLines = new();
+ private Dictionary _vertLinesReversed = new();
// Components
private NavMapComponent? _navMap;
@@ -376,7 +377,7 @@ public partial class NavMapControl : MapGridControl
var fontSize = (int) Math.Round(1 / WorldRange * DefaultDisplayedRange * UIScale * _targetFontsize, 0);
var font = new VectorFont(_cache.GetResource("/Fonts/NotoSans/NotoSans-Bold.ttf"), fontSize);
- foreach (var beacon in _navMap.Beacons)
+ foreach (var beacon in _navMap.Beacons.Values)
{
var position = beacon.Position - offset;
position = ScalePosition(position with { Y = -position.Y });
@@ -485,113 +486,106 @@ public partial class NavMapControl : MapGridControl
return;
// We'll use the following dictionaries to combine collinear wall lines
- HorizLinesLookup.Clear();
- HorizLinesLookupReversed.Clear();
- VertLinesLookup.Clear();
- VertLinesLookupReversed.Clear();
+ _horizLines.Clear();
+ _horizLinesReversed.Clear();
+ _vertLines.Clear();
+ _vertLinesReversed.Clear();
- foreach ((var (category, chunkOrigin), var chunk) in _navMap.Chunks)
+ const int southMask = (int) AtmosDirection.South << (int) NavMapChunkType.Wall;
+ const int eastMask = (int) AtmosDirection.East << (int) NavMapChunkType.Wall;
+ const int westMask = (int) AtmosDirection.West << (int) NavMapChunkType.Wall;
+ const int northMask = (int) AtmosDirection.North << (int) NavMapChunkType.Wall;
+
+ foreach (var (chunkOrigin, chunk) in _navMap.Chunks)
{
- if (category != NavMapChunkType.Wall)
- continue;
-
- for (var i = 0; i < SharedNavMapSystem.ChunkSize * SharedNavMapSystem.ChunkSize; i++)
+ for (var i = 0; i < SharedNavMapSystem.ArraySize; i++)
{
- var value = (ushort) Math.Pow(2, i);
- var mask = _navMapSystem.GetCombinedEdgesForChunk(chunk.TileData) & value;
-
- if (mask == 0x0)
+ var tileData = chunk.TileData[i] & SharedNavMapSystem.WallMask;
+ if (tileData == 0)
continue;
- var relativeTile = SharedNavMapSystem.GetTile(mask);
+ tileData >>= (int) NavMapChunkType.Wall;
+
+ var relativeTile = SharedNavMapSystem.GetTileFromIndex(i);
var tile = (chunk.Origin * SharedNavMapSystem.ChunkSize + relativeTile) * _grid.TileSize;
- if (!_navMapSystem.AllTileEdgesAreOccupied(chunk.TileData, relativeTile))
+ if (tileData != SharedNavMapSystem.AllDirMask)
{
- AddRectForThinWall(chunk.TileData, tile);
+ AddRectForThinWall(tileData, tile);
continue;
}
tile = tile with { Y = -tile.Y };
-
NavMapChunk? neighborChunk;
- bool neighbor;
// North edge
- if (relativeTile.Y == SharedNavMapSystem.ChunkSize - 1)
- {
- neighbor = _navMap.Chunks.TryGetValue((NavMapChunkType.Wall, chunkOrigin + new Vector2i(0, 1)), out neighborChunk) &&
- (neighborChunk.TileData[AtmosDirection.South] &
- SharedNavMapSystem.GetFlag(new Vector2i(relativeTile.X, 0))) != 0x0;
- }
- else
- {
- var flag = SharedNavMapSystem.GetFlag(relativeTile + new Vector2i(0, 1));
- neighbor = (chunk.TileData[AtmosDirection.South] & flag) != 0x0;
- }
+ var neighborData = 0;
+ if (relativeTile.Y != SharedNavMapSystem.ChunkSize - 1)
+ neighborData = chunk.TileData[i+1];
+ else if (_navMap.Chunks.TryGetValue(chunkOrigin + Vector2i.Up, out neighborChunk))
+ neighborData = neighborChunk.TileData[i + 1 - SharedNavMapSystem.ChunkSize];
- if (!neighbor)
- AddOrUpdateNavMapLine(tile + new Vector2i(0, -_grid.TileSize), tile + new Vector2i(_grid.TileSize, -_grid.TileSize), HorizLinesLookup, HorizLinesLookupReversed);
+ if ((neighborData & southMask) == 0)
+ {
+ AddOrUpdateNavMapLine(tile + new Vector2i(0, -_grid.TileSize),
+ tile + new Vector2i(_grid.TileSize, -_grid.TileSize), _horizLines,
+ _horizLinesReversed);
+ }
// East edge
- if (relativeTile.X == SharedNavMapSystem.ChunkSize - 1)
- {
- neighbor = _navMap.Chunks.TryGetValue((NavMapChunkType.Wall, chunkOrigin + new Vector2i(1, 0)), out neighborChunk) &&
- (neighborChunk.TileData[AtmosDirection.West] &
- SharedNavMapSystem.GetFlag(new Vector2i(0, relativeTile.Y))) != 0x0;
- }
- else
- {
- var flag = SharedNavMapSystem.GetFlag(relativeTile + new Vector2i(1, 0));
- neighbor = (chunk.TileData[AtmosDirection.West] & flag) != 0x0;
- }
+ neighborData = 0;
+ if (relativeTile.X != SharedNavMapSystem.ChunkSize - 1)
+ neighborData = chunk.TileData[i+SharedNavMapSystem.ChunkSize];
+ else if (_navMap.Chunks.TryGetValue(chunkOrigin + Vector2i.Right, out neighborChunk))
+ neighborData = neighborChunk.TileData[i + SharedNavMapSystem.ChunkSize - SharedNavMapSystem.ArraySize];
- if (!neighbor)
- AddOrUpdateNavMapLine(tile + new Vector2i(_grid.TileSize, -_grid.TileSize), tile + new Vector2i(_grid.TileSize, 0), VertLinesLookup, VertLinesLookupReversed);
+ if ((neighborData & westMask) == 0)
+ {
+ AddOrUpdateNavMapLine(tile + new Vector2i(_grid.TileSize, -_grid.TileSize),
+ tile + new Vector2i(_grid.TileSize, 0), _vertLines, _vertLinesReversed);
+ }
// South edge
- if (relativeTile.Y == 0)
- {
- neighbor = _navMap.Chunks.TryGetValue((NavMapChunkType.Wall, chunkOrigin + new Vector2i(0, -1)), out neighborChunk) &&
- (neighborChunk.TileData[AtmosDirection.North] &
- SharedNavMapSystem.GetFlag(new Vector2i(relativeTile.X, SharedNavMapSystem.ChunkSize - 1))) != 0x0;
- }
- else
- {
- var flag = SharedNavMapSystem.GetFlag(relativeTile + new Vector2i(0, -1));
- neighbor = (chunk.TileData[AtmosDirection.North] & flag) != 0x0;
- }
+ neighborData = 0;
+ if (relativeTile.Y != 0)
+ neighborData = chunk.TileData[i-1];
+ else if (_navMap.Chunks.TryGetValue(chunkOrigin + Vector2i.Down, out neighborChunk))
+ neighborData = neighborChunk.TileData[i - 1 + SharedNavMapSystem.ChunkSize];
- if (!neighbor)
- AddOrUpdateNavMapLine(tile, tile + new Vector2i(_grid.TileSize, 0), HorizLinesLookup, HorizLinesLookupReversed);
+ if ((neighborData & northMask) == 0)
+ {
+ AddOrUpdateNavMapLine(tile, tile + new Vector2i(_grid.TileSize, 0), _horizLines,
+ _horizLinesReversed);
+ }
// West edge
- if (relativeTile.X == 0)
- {
- neighbor = _navMap.Chunks.TryGetValue((NavMapChunkType.Wall, chunkOrigin + new Vector2i(-1, 0)), out neighborChunk) &&
- (neighborChunk.TileData[AtmosDirection.East] &
- SharedNavMapSystem.GetFlag(new Vector2i(SharedNavMapSystem.ChunkSize - 1, relativeTile.Y))) != 0x0;
- }
- else
- {
- var flag = SharedNavMapSystem.GetFlag(relativeTile + new Vector2i(-1, 0));
- neighbor = (chunk.TileData[AtmosDirection.East] & flag) != 0x0;
- }
+ neighborData = 0;
+ if (relativeTile.X != 0)
+ neighborData = chunk.TileData[i-SharedNavMapSystem.ChunkSize];
+ else if (_navMap.Chunks.TryGetValue(chunkOrigin + Vector2i.Left, out neighborChunk))
+ neighborData = neighborChunk.TileData[i - SharedNavMapSystem.ChunkSize + SharedNavMapSystem.ArraySize];
- if (!neighbor)
- AddOrUpdateNavMapLine(tile + new Vector2i(0, -_grid.TileSize), tile, VertLinesLookup, VertLinesLookupReversed);
+ if ((neighborData & eastMask) == 0)
+ {
+ AddOrUpdateNavMapLine(tile + new Vector2i(0, -_grid.TileSize), tile, _vertLines,
+ _vertLinesReversed);
+ }
// Add a diagonal line for interiors. Unless there are a lot of double walls, there is no point combining these
TileLines.Add((tile + new Vector2(0, -_grid.TileSize), tile + new Vector2(_grid.TileSize, 0)));
}
}
- // Record the combined lines
- foreach (var (origin, terminal) in HorizLinesLookup)
- TileLines.Add((origin.Item2, terminal.Item2));
+ // Record the combined lines
+ foreach (var (origin, terminal) in _horizLines)
+ {
+ TileLines.Add((origin, terminal));
+ }
- foreach (var (origin, terminal) in VertLinesLookup)
- TileLines.Add((origin.Item2, terminal.Item2));
+ foreach (var (origin, terminal) in _vertLines)
+ {
+ TileLines.Add((origin, terminal));
+ }
}
private void UpdateNavMapAirlocks()
@@ -599,26 +593,23 @@ public partial class NavMapControl : MapGridControl
if (_navMap == null || _grid == null)
return;
- foreach (var ((category, _), chunk) in _navMap.Chunks)
+ foreach (var chunk in _navMap.Chunks.Values)
{
- if (category != NavMapChunkType.Airlock)
- continue;
-
- for (var i = 0; i < SharedNavMapSystem.ChunkSize * SharedNavMapSystem.ChunkSize; i++)
+ for (var i = 0; i < SharedNavMapSystem.ArraySize; i++)
{
- var value = (int) Math.Pow(2, i);
- var mask = _navMapSystem.GetCombinedEdgesForChunk(chunk.TileData) & value;
-
- if (mask == 0x0)
+ var tileData = chunk.TileData[i] & SharedNavMapSystem.AirlockMask;
+ if (tileData == 0)
continue;
- var relative = SharedNavMapSystem.GetTile(mask);
+ tileData >>= (int) NavMapChunkType.Airlock;
+
+ var relative = SharedNavMapSystem.GetTileFromIndex(i);
var tile = (chunk.Origin * SharedNavMapSystem.ChunkSize + relative) * _grid.TileSize;
// If the edges of an airlock tile are not all occupied, draw a thin airlock for each edge
- if (!_navMapSystem.AllTileEdgesAreOccupied(chunk.TileData, relative))
+ if (tileData != SharedNavMapSystem.AllDirMask)
{
- AddRectForThinAirlock(chunk.TileData, tile);
+ AddRectForThinAirlock(tileData, tile);
continue;
}
@@ -632,108 +623,90 @@ public partial class NavMapControl : MapGridControl
}
}
- private void AddRectForThinWall(Dictionary tileData, Vector2i tile)
+ private void AddRectForThinWall(int tileData, Vector2i tile)
{
- if (_navMapSystem == null || _grid == null)
- return;
+ var leftTop = new Vector2(-0.5f, 0.5f - ThinWallThickness);
+ var rightBottom = new Vector2(0.5f, 0.5f);
- var leftTop = new Vector2(-0.5f, -0.5f + ThinWallThickness);
- var rightBottom = new Vector2(0.5f, -0.5f);
-
- foreach (var (direction, mask) in tileData)
+ for (var i = 0; i < SharedNavMapSystem.Directions; i++)
{
- var relative = SharedMapSystem.GetChunkRelative(tile, SharedNavMapSystem.ChunkSize);
- var flag = (ushort) SharedNavMapSystem.GetFlag(relative);
-
- if ((mask & flag) == 0)
+ var dirMask = 1 << i;
+ if ((tileData & dirMask) == 0)
continue;
var tilePosition = new Vector2(tile.X + 0.5f, -tile.Y - 0.5f);
- var angle = new Angle(0);
-
- switch (direction)
- {
- case AtmosDirection.East: angle = new Angle(MathF.PI * 0.5f); break;
- case AtmosDirection.South: angle = new Angle(MathF.PI); break;
- case AtmosDirection.West: angle = new Angle(MathF.PI * -0.5f); break;
- }
+ // TODO NAVMAP
+ // Consider using faster rotation operations, given that these are always 90 degree increments
+ var angle = -((AtmosDirection) dirMask).ToAngle();
TileRects.Add((angle.RotateVec(leftTop) + tilePosition, angle.RotateVec(rightBottom) + tilePosition));
}
}
- private void AddRectForThinAirlock(Dictionary tileData, Vector2i tile)
+ private void AddRectForThinAirlock(int tileData, Vector2i tile)
{
- if (_navMapSystem == null || _grid == null)
- return;
+ var leftTop = new Vector2(-0.5f + FullWallInstep, 0.5f - FullWallInstep - ThinDoorThickness);
+ var rightBottom = new Vector2(0.5f - FullWallInstep, 0.5f - FullWallInstep);
+ var centreTop = new Vector2(0f, 0.5f - FullWallInstep - ThinDoorThickness);
+ var centreBottom = new Vector2(0f, 0.5f - FullWallInstep);
- var leftTop = new Vector2(-0.5f + FullWallInstep, -0.5f + FullWallInstep + ThinDoorThickness);
- var rightBottom = new Vector2(0.5f - FullWallInstep, -0.5f + FullWallInstep);
- var centreTop = new Vector2(0f, -0.5f + FullWallInstep + ThinDoorThickness);
- var centreBottom = new Vector2(0f, -0.5f + FullWallInstep);
-
- foreach (var (direction, mask) in tileData)
+ for (var i = 0; i < SharedNavMapSystem.Directions; i++)
{
- var relative = SharedMapSystem.GetChunkRelative(tile, SharedNavMapSystem.ChunkSize);
- var flag = (ushort) SharedNavMapSystem.GetFlag(relative);
-
- if ((mask & flag) == 0)
+ var dirMask = 1 << i;
+ if ((tileData & dirMask) == 0)
continue;
var tilePosition = new Vector2(tile.X + 0.5f, -tile.Y - 0.5f);
- var angle = new Angle(0);
-
- switch (direction)
- {
- case AtmosDirection.East: angle = new Angle(MathF.PI * 0.5f);break;
- case AtmosDirection.South: angle = new Angle(MathF.PI); break;
- case AtmosDirection.West: angle = new Angle(MathF.PI * -0.5f); break;
- }
-
+ var angle = -((AtmosDirection) dirMask).ToAngle();
TileRects.Add((angle.RotateVec(leftTop) + tilePosition, angle.RotateVec(rightBottom) + tilePosition));
TileLines.Add((angle.RotateVec(centreTop) + tilePosition, angle.RotateVec(centreBottom) + tilePosition));
}
}
- protected void AddOrUpdateNavMapLine
- (Vector2i origin,
+ protected void AddOrUpdateNavMapLine(
+ Vector2i origin,
Vector2i terminus,
- Dictionary<(int, Vector2i), (int, Vector2i)> lookup,
- Dictionary<(int, Vector2i), (int, Vector2i)> lookupReversed,
- int index = 0)
+ Dictionary lookup,
+ Dictionary lookupReversed)
{
- (int, Vector2i) foundTermiusTuple;
- (int, Vector2i) foundOriginTuple;
+ Vector2i foundTermius;
+ Vector2i foundOrigin;
- if (lookup.TryGetValue((index, terminus), out foundTermiusTuple) &&
- lookupReversed.TryGetValue((index, origin), out foundOriginTuple))
+ // Does our new line end at the beginning of an existing line?
+ if (lookup.Remove(terminus, out foundTermius))
{
- lookup[foundOriginTuple] = foundTermiusTuple;
- lookupReversed[foundTermiusTuple] = foundOriginTuple;
+ DebugTools.Assert(lookupReversed[foundTermius] == terminus);
- lookup.Remove((index, terminus));
- lookupReversed.Remove((index, origin));
+ // Does our new line start at the end of an existing line?
+ if (lookupReversed.Remove(origin, out foundOrigin))
+ {
+ // Our new line just connects two existing lines
+ DebugTools.Assert(lookup[foundOrigin] == origin);
+ lookup[foundOrigin] = foundTermius;
+ lookupReversed[foundTermius] = foundOrigin;
+ }
+ else
+ {
+ // Our new line precedes an existing line, extending it further to the left
+ lookup[origin] = foundTermius;
+ lookupReversed[foundTermius] = origin;
+ }
+ return;
}
- else if (lookup.TryGetValue((index, terminus), out foundTermiusTuple))
+ // Does our new line start at the end of an existing line?
+ if (lookupReversed.Remove(origin, out foundOrigin))
{
- lookup[(index, origin)] = foundTermiusTuple;
- lookup.Remove((index, terminus));
- lookupReversed[foundTermiusTuple] = (index, origin);
+ // Our new line just extends an existing line further to the right
+ DebugTools.Assert(lookup[foundOrigin] == origin);
+ lookup[foundOrigin] = terminus;
+ lookupReversed[terminus] = foundOrigin;
+ return;
}
- else if (lookupReversed.TryGetValue((index, origin), out foundOriginTuple))
- {
- lookupReversed[(index, terminus)] = foundOriginTuple;
- lookupReversed.Remove(foundOriginTuple);
- lookup[foundOriginTuple] = (index, terminus);
- }
-
- else
- {
- lookup.Add((index, origin), (index, terminus));
- lookupReversed.Add((index, terminus), (index, origin));
- }
+ // Completely disconnected line segment.
+ lookup.Add(origin, terminus);
+ lookupReversed.Add(terminus, origin);
}
protected Vector2 GetOffset()
diff --git a/Content.Client/Power/PowerMonitoringConsoleNavMapControl.cs b/Content.Client/Power/PowerMonitoringConsoleNavMapControl.cs
index 3d94318be8..d5057416cf 100644
--- a/Content.Client/Power/PowerMonitoringConsoleNavMapControl.cs
+++ b/Content.Client/Power/PowerMonitoringConsoleNavMapControl.cs
@@ -5,6 +5,7 @@ using Robust.Client.Graphics;
using Robust.Shared.Collections;
using Robust.Shared.Map.Components;
using System.Numerics;
+using static Content.Shared.Power.SharedPowerMonitoringConsoleSystem;
namespace Content.Client.Power;
@@ -26,6 +27,11 @@ public sealed partial class PowerMonitoringConsoleNavMapControl : NavMapControl
public List PowerCableNetwork = new();
public List FocusCableNetwork = new();
+ private Dictionary[] _horizLines = [new(), new(), new()];
+ private Dictionary[] _horizLinesReversed = [new(), new(), new()];
+ private Dictionary[] _vertLines = [new(), new(), new()];
+ private Dictionary[] _vertLinesReversed = [new(), new(), new()];
+
private MapGridComponent? _grid;
public PowerMonitoringConsoleNavMapControl() : base()
@@ -182,28 +188,32 @@ public sealed partial class PowerMonitoringConsoleNavMapControl : NavMapControl
if (chunks == null)
return decodedOutput;
- // We'll use the following dictionaries to combine collinear power cable lines
- HorizLinesLookup.Clear();
- HorizLinesLookupReversed.Clear();
- VertLinesLookup.Clear();
- VertLinesLookupReversed.Clear();
+ Array.ForEach(_horizLines, x=> x.Clear());
+ Array.ForEach(_horizLinesReversed, x=> x.Clear());
+ Array.ForEach(_vertLines, x=> x.Clear());
+ Array.ForEach(_vertLinesReversed, x=> x.Clear());
- foreach ((var chunkOrigin, var chunk) in chunks)
+ foreach (var (chunkOrigin, chunk) in chunks)
{
- for (int cableIdx = 0; cableIdx < chunk.PowerCableData.Length; cableIdx++)
+ for (var cableIdx = 0; cableIdx < 3; cableIdx++)
{
+ var horizLines = _horizLines[cableIdx];
+ var horizLinesReversed = _horizLinesReversed[cableIdx];
+ var vertLines = _vertLines[cableIdx];
+ var vertLinesReversed = _vertLinesReversed[cableIdx];
+
var chunkMask = chunk.PowerCableData[cableIdx];
- for (var chunkIdx = 0; chunkIdx < SharedNavMapSystem.ChunkSize * SharedNavMapSystem.ChunkSize; chunkIdx++)
+ for (var chunkIdx = 0; chunkIdx < ChunkSize * ChunkSize; chunkIdx++)
{
- var value = (int) Math.Pow(2, chunkIdx);
+ var value = 1 << chunkIdx;
var mask = chunkMask & value;
if (mask == 0x0)
continue;
- var relativeTile = SharedNavMapSystem.GetTile(mask);
- var tile = (chunk.Origin * SharedNavMapSystem.ChunkSize + relativeTile) * _grid.TileSize;
+ var relativeTile = GetTileFromIndex(chunkIdx);
+ var tile = (chunk.Origin * ChunkSize + relativeTile) * _grid.TileSize;
tile = tile with { Y = -tile.Y };
PowerCableChunk neighborChunk;
@@ -212,39 +222,39 @@ public sealed partial class PowerMonitoringConsoleNavMapControl : NavMapControl
// Note: we only check the north and east neighbors
// East
- if (relativeTile.X == SharedNavMapSystem.ChunkSize - 1)
+ if (relativeTile.X == ChunkSize - 1)
{
neighbor = chunks.TryGetValue(chunkOrigin + new Vector2i(1, 0), out neighborChunk) &&
- (neighborChunk.PowerCableData[cableIdx] & SharedNavMapSystem.GetFlag(new Vector2i(0, relativeTile.Y))) != 0x0;
+ (neighborChunk.PowerCableData[cableIdx] & GetFlag(new Vector2i(0, relativeTile.Y))) != 0x0;
}
else
{
- var flag = SharedNavMapSystem.GetFlag(relativeTile + new Vector2i(1, 0));
+ var flag = GetFlag(relativeTile + new Vector2i(1, 0));
neighbor = (chunkMask & flag) != 0x0;
}
if (neighbor)
{
// Add points
- AddOrUpdateNavMapLine(tile, tile + new Vector2i(_grid.TileSize, 0), HorizLinesLookup, HorizLinesLookupReversed, cableIdx);
+ AddOrUpdateNavMapLine(tile, tile + new Vector2i(_grid.TileSize, 0), horizLines, horizLinesReversed);
}
// North
- if (relativeTile.Y == SharedNavMapSystem.ChunkSize - 1)
+ if (relativeTile.Y == ChunkSize - 1)
{
neighbor = chunks.TryGetValue(chunkOrigin + new Vector2i(0, 1), out neighborChunk) &&
- (neighborChunk.PowerCableData[cableIdx] & SharedNavMapSystem.GetFlag(new Vector2i(relativeTile.X, 0))) != 0x0;
+ (neighborChunk.PowerCableData[cableIdx] & GetFlag(new Vector2i(relativeTile.X, 0))) != 0x0;
}
else
{
- var flag = SharedNavMapSystem.GetFlag(relativeTile + new Vector2i(0, 1));
+ var flag = GetFlag(relativeTile + new Vector2i(0, 1));
neighbor = (chunkMask & flag) != 0x0;
}
if (neighbor)
{
// Add points
- AddOrUpdateNavMapLine(tile + new Vector2i(0, -_grid.TileSize), tile, VertLinesLookup, VertLinesLookupReversed, cableIdx);
+ AddOrUpdateNavMapLine(tile + new Vector2i(0, -_grid.TileSize), tile, vertLines, vertLinesReversed);
}
}
@@ -253,11 +263,25 @@ public sealed partial class PowerMonitoringConsoleNavMapControl : NavMapControl
var gridOffset = new Vector2(_grid.TileSize * 0.5f, -_grid.TileSize * 0.5f);
- foreach (var (origin, terminal) in HorizLinesLookup)
- decodedOutput.Add(new PowerMonitoringConsoleLine(origin.Item2 + gridOffset, terminal.Item2 + gridOffset, (PowerMonitoringConsoleLineGroup) origin.Item1));
+ for (var index = 0; index < _horizLines.Length; index++)
+ {
+ var horizLines = _horizLines[index];
+ foreach (var (origin, terminal) in horizLines)
+ {
+ decodedOutput.Add(new PowerMonitoringConsoleLine(origin + gridOffset, terminal + gridOffset,
+ (PowerMonitoringConsoleLineGroup) index));
+ }
+ }
- foreach (var (origin, terminal) in VertLinesLookup)
- decodedOutput.Add(new PowerMonitoringConsoleLine(origin.Item2 + gridOffset, terminal.Item2 + gridOffset, (PowerMonitoringConsoleLineGroup) origin.Item1));
+ for (var index = 0; index < _vertLines.Length; index++)
+ {
+ var vertLines = _vertLines[index];
+ foreach (var (origin, terminal) in vertLines)
+ {
+ decodedOutput.Add(new PowerMonitoringConsoleLine(origin + gridOffset, terminal + gridOffset,
+ (PowerMonitoringConsoleLineGroup) index));
+ }
+ }
return decodedOutput;
}
diff --git a/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs b/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs
index 70b7608f6d..dad20a641f 100644
--- a/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs
+++ b/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs
@@ -742,7 +742,6 @@ namespace Content.Client.Preferences.UI
CharacterSlot = _preferencesManager.Preferences.SelectedCharacterIndex;
UpdateAntagRequirements();
- UpdateRoleRequirements();
UpdateControls();
ShowClothes.Pressed = true;
}
diff --git a/Content.Client/UserInterface/Systems/Ghost/Controls/GhostTargetWindow.xaml b/Content.Client/UserInterface/Systems/Ghost/Controls/GhostTargetWindow.xaml
index 86fd09b2c8..32cab732d1 100644
--- a/Content.Client/UserInterface/Systems/Ghost/Controls/GhostTargetWindow.xaml
+++ b/Content.Client/UserInterface/Systems/Ghost/Controls/GhostTargetWindow.xaml
@@ -1,5 +1,6 @@
+
diff --git a/Content.Client/UserInterface/Systems/Ghost/Controls/GhostTargetWindow.xaml.cs b/Content.Client/UserInterface/Systems/Ghost/Controls/GhostTargetWindow.xaml.cs
index 3c17697c25..9a20226fdf 100644
--- a/Content.Client/UserInterface/Systems/Ghost/Controls/GhostTargetWindow.xaml.cs
+++ b/Content.Client/UserInterface/Systems/Ghost/Controls/GhostTargetWindow.xaml.cs
@@ -15,11 +15,14 @@ namespace Content.Client.UserInterface.Systems.Ghost.Controls
private string _searchText = string.Empty;
public event Action? WarpClicked;
+ public event Action? OnGhostnadoClicked;
public GhostTargetWindow()
{
RobustXamlLoader.Load(this);
SearchBar.OnTextChanged += OnSearchTextChanged;
+
+ GhostnadoButton.OnPressed += _ => OnGhostnadoClicked?.Invoke();
}
public void UpdateWarps(IEnumerable warps)
diff --git a/Content.Client/UserInterface/Systems/Ghost/GhostUIController.cs b/Content.Client/UserInterface/Systems/Ghost/GhostUIController.cs
index 12d6c65953..53779ea41c 100644
--- a/Content.Client/UserInterface/Systems/Ghost/GhostUIController.cs
+++ b/Content.Client/UserInterface/Systems/Ghost/GhostUIController.cs
@@ -111,6 +111,12 @@ public sealed class GhostUIController : UIController, IOnSystemChanged(animationUid);
+ track.User = user;
_animation.Play(animationUid, GetSlashAnimation(sprite, angle, spriteRotation), SlashAnimationKey);
- TransformSystem.SetParent(animationUid, xform, user, userXform);
if (arcComponent.Fadeout)
_animation.Play(animationUid, GetFadeAnimation(sprite, 0.065f, 0.065f + 0.05f), FadeAnimationKey);
break;
case WeaponArcAnimation.Thrust:
+ track = EnsureComp(animationUid);
+ track.User = user;
_animation.Play(animationUid, GetThrustAnimation(sprite, distance, spriteRotation), ThrustAnimationKey);
- TransformSystem.SetParent(animationUid, xform, user, userXform);
if (arcComponent.Fadeout)
_animation.Play(animationUid, GetFadeAnimation(sprite, 0.05f, 0.15f), FadeAnimationKey);
break;
case WeaponArcAnimation.None:
var (mapPos, mapRot) = TransformSystem.GetWorldPositionRotation(userXform);
- TransformSystem.AttachToGridOrMap(animationUid, xform);
var worldPos = mapPos + (mapRot - userXform.LocalRotation).RotateVec(localPos);
var newLocalPos = TransformSystem.GetInvWorldMatrix(xform.ParentUid).Transform(worldPos);
- TransformSystem.SetLocalPositionNoLerp(xform, newLocalPos);
+ TransformSystem.SetLocalPositionNoLerp(animationUid, newLocalPos, xform);
if (arcComponent.Fadeout)
_animation.Play(animationUid, GetFadeAnimation(sprite, 0f, 0.15f), FadeAnimationKey);
break;
//CrystallPunk MeleeUpgrade
case WeaponArcAnimation.CPSlash:
+ track = EnsureComp(animationUid);
+ track.User = user;
_animation.Play(animationUid, CPGetSlashAnimation(sprite, angle, spriteRotation, length, offset), SlashAnimationKey);
- TransformSystem.SetParent(animationUid, xform, user, userXform);
if (arcComponent.Fadeout)
_animation.Play(animationUid, GetFadeAnimation(sprite, length * 0.5f, length + 0.15f), FadeAnimationKey);
break;
case WeaponArcAnimation.CPThrust:
+ track = EnsureComp(animationUid);
+ track.User = user;
_animation.Play(animationUid, CPGetThrustAnimation(sprite, -offset, spriteRotation, length), ThrustAnimationKey);
- TransformSystem.SetParent(animationUid, xform, user, userXform);
if (arcComponent.Fadeout)
_animation.Play(animationUid, GetFadeAnimation(sprite, 0f, 0.15f), FadeAnimationKey);
break;
@@ -118,7 +122,6 @@ public sealed partial class MeleeWeaponSystem
var endRotationOffset = endRotation.RotateVec(new Vector2(0f, -1f));
startRotation += spriteRotation;
endRotation += spriteRotation;
- sprite.NoRotation = true;
return new Animation()
{
@@ -218,7 +221,7 @@ public sealed partial class MeleeWeaponSystem
InterpolationMode = AnimationInterpolationMode.Linear,
KeyFrames =
{
- new AnimationTrackProperty.KeyFrame(Vector2.Zero, 0f), //CrystallPunk MeleeUpgrade
+ new AnimationTrackProperty.KeyFrame(Vector2.Zero, 0f), //CrystallPunk MeleeUpgrade
new AnimationTrackProperty.KeyFrame(direction.Normalized() * 0.15f, length*0.4f), //CrystallPunk MeleeUpgrade
new AnimationTrackProperty.KeyFrame(Vector2.Zero, length*0.8f) //CrystallPunk MeleeUpgrade
}
@@ -227,6 +230,29 @@ public sealed partial class MeleeWeaponSystem
};
}
+ ///
+ /// Updates the effect positions to follow the user
+ ///
+ private void UpdateEffects()
+ {
+ var query = EntityQueryEnumerator();
+ while (query.MoveNext(out var arcComponent, out var xform))
+ {
+ if (arcComponent.User == null)
+ continue;
+
+ Vector2 targetPos = TransformSystem.GetWorldPosition(arcComponent.User.Value);
+
+ if (arcComponent.Offset != Vector2.Zero)
+ {
+ var entRotation = TransformSystem.GetWorldRotation(xform);
+ targetPos += entRotation.RotateVec(arcComponent.Offset);
+ }
+
+ TransformSystem.SetWorldPosition(xform, targetPos);
+ }
+ }
+
//CrystallPunk MeleeUpgrade start
private Animation CPGetSlashAnimation(SpriteComponent sprite, Angle arc, Angle spriteRotation, float length, float offset = -1f)
{
diff --git a/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs b/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs
index 641d56d3d1..039af55bd0 100644
--- a/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs
+++ b/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs
@@ -43,6 +43,12 @@ public sealed partial class MeleeWeaponSystem : SharedMeleeWeaponSystem
UpdatesOutsidePrediction = true;
}
+ public override void FrameUpdate(float frameTime)
+ {
+ base.FrameUpdate(frameTime);
+ UpdateEffects();
+ }
+
public override void Update(float frameTime)
{
base.Update(frameTime);
diff --git a/Content.Client/Weapons/Ranged/Systems/GunSystem.cs b/Content.Client/Weapons/Ranged/Systems/GunSystem.cs
index 9e50cab3e1..5aba04bdf8 100644
--- a/Content.Client/Weapons/Ranged/Systems/GunSystem.cs
+++ b/Content.Client/Weapons/Ranged/Systems/GunSystem.cs
@@ -1,4 +1,5 @@
using System.Numerics;
+using Content.Client.Animations;
using Content.Client.Items;
using Content.Client.Weapons.Ranged.Components;
using Content.Shared.Camera;
@@ -15,6 +16,7 @@ using Robust.Client.Player;
using Robust.Shared.Animations;
using Robust.Shared.Input;
using Robust.Shared.Map;
+using Robust.Shared.Map.Components;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
using SharedGunSystem = Content.Shared.Weapons.Ranged.Systems.SharedGunSystem;
@@ -24,13 +26,14 @@ namespace Content.Client.Weapons.Ranged.Systems;
public sealed partial class GunSystem : SharedGunSystem
{
+ [Dependency] private readonly IComponentFactory _factory = default!;
[Dependency] private readonly IEyeManager _eyeManager = default!;
[Dependency] private readonly IInputManager _inputManager = default!;
[Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly AnimationPlayerSystem _animPlayer = default!;
[Dependency] private readonly InputSystem _inputSystem = default!;
[Dependency] private readonly SharedCameraRecoilSystem _recoil = default!;
- [Dependency] private readonly IComponentFactory _factory = default!;
+ [Dependency] private readonly SharedMapSystem _maps = default!;
[ValidatePrototypeId]
public const string HitscanProto = "HitscanEffect";
@@ -123,7 +126,7 @@ public sealed partial class GunSystem : SharedGunSystem
}
};
- _animPlayer.Play(ent, null, anim, "hitscan-effect");
+ _animPlayer.Play(ent, anim, "hitscan-effect");
}
}
@@ -189,6 +192,7 @@ public sealed partial class GunSystem : SharedGunSystem
// to just delete the spawned entities. This is for programmer sanity despite the wasted perf.
// This also means any ammo specific stuff can be grabbed as necessary.
var direction = fromCoordinates.ToMapPos(EntityManager, TransformSystem) - toCoordinates.ToMapPos(EntityManager, TransformSystem);
+ var worldAngle = direction.ToAngle().Opposite();
foreach (var (ent, shootable) in ammo)
{
@@ -208,7 +212,7 @@ public sealed partial class GunSystem : SharedGunSystem
if (!cartridge.Spent)
{
SetCartridgeSpent(ent!.Value, cartridge, true);
- MuzzleFlash(gunUid, cartridge, user);
+ MuzzleFlash(gunUid, cartridge, worldAngle, user);
Audio.PlayPredicted(gun.SoundGunshotModified, gunUid, user);
Recoil(user, direction, gun.CameraRecoilScalarModified);
// TODO: Can't predict entity deletions.
@@ -226,7 +230,7 @@ public sealed partial class GunSystem : SharedGunSystem
break;
case AmmoComponent newAmmo:
- MuzzleFlash(gunUid, newAmmo, user);
+ MuzzleFlash(gunUid, newAmmo, worldAngle, user);
Audio.PlayPredicted(gun.SoundGunshotModified, gunUid, user);
Recoil(user, direction, gun.CameraRecoilScalarModified);
if (IsClientSide(ent!.Value))
@@ -258,33 +262,41 @@ public sealed partial class GunSystem : SharedGunSystem
PopupSystem.PopupEntity(message, uid.Value, user.Value);
}
- protected override void CreateEffect(EntityUid uid, MuzzleFlashEvent message, EntityUid? user = null)
+ protected override void CreateEffect(EntityUid gunUid, MuzzleFlashEvent message, EntityUid? user = null)
{
if (!Timing.IsFirstTimePredicted)
return;
+ var gunXform = Transform(gunUid);
+ var gridUid = gunXform.GridUid;
EntityCoordinates coordinates;
- if (message.MatchRotation)
- coordinates = new EntityCoordinates(uid, Vector2.Zero);
- else if (TryComp(uid, out var xform))
- coordinates = xform.Coordinates;
+ if (TryComp(gridUid, out MapGridComponent? mapGrid))
+ {
+ coordinates = new EntityCoordinates(gridUid.Value, _maps.LocalToGrid(gridUid.Value, mapGrid, gunXform.Coordinates));
+ }
+ else if (gunXform.MapUid != null)
+ {
+ coordinates = new EntityCoordinates(gunXform.MapUid.Value, TransformSystem.GetWorldPosition(gunXform));
+ }
else
+ {
return;
-
- if (!coordinates.IsValid(EntityManager))
- return;
+ }
var ent = Spawn(message.Prototype, coordinates);
+ TransformSystem.SetWorldRotationNoLerp(ent, message.Angle);
- var effectXform = Transform(ent);
- TransformSystem.SetLocalPositionRotation(effectXform,
- effectXform.LocalPosition + new Vector2(0f, -0.5f),
- effectXform.LocalRotation - MathF.PI / 2);
+ if (user != null)
+ {
+ var track = EnsureComp(ent);
+ track.User = user;
+ track.Offset = Vector2.UnitX / 2f;
+ }
var lifetime = 0.4f;
- if (TryComp(uid, out var despawn))
+ if (TryComp(gunUid, out var despawn))
{
lifetime = despawn.Lifetime;
}
@@ -309,18 +321,17 @@ public sealed partial class GunSystem : SharedGunSystem
};
_animPlayer.Play(ent, anim, "muzzle-flash");
- if (!TryComp(uid, out PointLightComponent? light))
+ if (!TryComp(gunUid, out PointLightComponent? light))
{
light = (PointLightComponent) _factory.GetComponent(typeof(PointLightComponent));
- light.Owner = uid;
light.NetSyncEnabled = false;
- AddComp(uid, light);
+ AddComp(gunUid, light);
}
- Lights.SetEnabled(uid, true, light);
- Lights.SetRadius(uid, 2f, light);
- Lights.SetColor(uid, Color.FromHex("#cc8e2b"), light);
- Lights.SetEnergy(uid, 5f, light);
+ Lights.SetEnabled(gunUid, true, light);
+ Lights.SetRadius(gunUid, 2f, light);
+ Lights.SetColor(gunUid, Color.FromHex("#cc8e2b"), light);
+ Lights.SetEnergy(gunUid, 5f, light);
var animTwo = new Animation()
{
@@ -352,9 +363,9 @@ public sealed partial class GunSystem : SharedGunSystem
}
};
- var uidPlayer = EnsureComp(uid);
+ var uidPlayer = EnsureComp(gunUid);
- _animPlayer.Stop(uid, uidPlayer, "muzzle-flash-light");
- _animPlayer.Play(uid, uidPlayer, animTwo,"muzzle-flash-light");
+ _animPlayer.Stop(gunUid, uidPlayer, "muzzle-flash-light");
+ _animPlayer.Play((gunUid, uidPlayer), animTwo,"muzzle-flash-light");
}
}
diff --git a/Content.Server/Administration/Systems/AdminVerbSystem.Antags.cs b/Content.Server/Administration/Systems/AdminVerbSystem.Antags.cs
index 599485150a..4103b8a8aa 100644
--- a/Content.Server/Administration/Systems/AdminVerbSystem.Antags.cs
+++ b/Content.Server/Administration/Systems/AdminVerbSystem.Antags.cs
@@ -44,9 +44,11 @@ public sealed partial class AdminVerbSystem
if (!_adminManager.HasAdminFlag(player, AdminFlags.Fun))
return;
- if (!HasComp(args.Target))
+ if (!HasComp(args.Target) || !TryComp(args.Target, out var targetActor))
return;
+ var targetPlayer = targetActor.PlayerSession;
+
Verb traitor = new()
{
Text = Loc.GetString("admin-verb-text-make-traitor"),
@@ -54,7 +56,7 @@ public sealed partial class AdminVerbSystem
Icon = new SpriteSpecifier.Rsi(new ResPath("/Textures/Structures/Wallmounts/posters.rsi"), "poster5_contraband"),
Act = () =>
{
- _antag.ForceMakeAntag(player, DefaultTraitorRule);
+ _antag.ForceMakeAntag(targetPlayer, DefaultTraitorRule);
},
Impact = LogImpact.High,
Message = Loc.GetString("admin-verb-make-traitor"),
@@ -83,7 +85,7 @@ public sealed partial class AdminVerbSystem
Icon = new SpriteSpecifier.Rsi(new("/Textures/Structures/Wallmounts/signs.rsi"), "radiation"),
Act = () =>
{
- _antag.ForceMakeAntag(player, DefaultNukeOpRule);
+ _antag.ForceMakeAntag(targetPlayer, DefaultNukeOpRule);
},
Impact = LogImpact.High,
Message = Loc.GetString("admin-verb-make-nuclear-operative"),
@@ -112,7 +114,7 @@ public sealed partial class AdminVerbSystem
Icon = new SpriteSpecifier.Rsi(new("/Textures/Interface/Misc/job_icons.rsi"), "HeadRevolutionary"),
Act = () =>
{
- _antag.ForceMakeAntag(player, DefaultRevsRule);
+ _antag.ForceMakeAntag(targetPlayer, DefaultRevsRule);
},
Impact = LogImpact.High,
Message = Loc.GetString("admin-verb-make-head-rev"),
@@ -126,7 +128,7 @@ public sealed partial class AdminVerbSystem
Icon = new SpriteSpecifier.Rsi(new ResPath("/Textures/Clothing/Hands/Gloves/Color/black.rsi"), "icon"),
Act = () =>
{
- _antag.ForceMakeAntag(player, DefaultThiefRule);
+ _antag.ForceMakeAntag(targetPlayer, DefaultThiefRule);
},
Impact = LogImpact.High,
Message = Loc.GetString("admin-verb-make-thief"),
diff --git a/Content.Server/Atmos/Components/GasMixtureHolderComponent.cs b/Content.Server/Atmos/Components/GasMixtureHolderComponent.cs
index 9d533f6ec4..98feb43346 100644
--- a/Content.Server/Atmos/Components/GasMixtureHolderComponent.cs
+++ b/Content.Server/Atmos/Components/GasMixtureHolderComponent.cs
@@ -1,4 +1,6 @@
-namespace Content.Server.Atmos.Components
+using Content.Shared.Atmos;
+
+namespace Content.Server.Atmos.Components
{
[RegisterComponent]
public sealed partial class GasMixtureHolderComponent : Component, IGasMixtureHolder
diff --git a/Content.Server/Atmos/Components/MapAtmosphereComponent.cs b/Content.Server/Atmos/Components/MapAtmosphereComponent.cs
index 6bdef901d4..bdd05e7849 100644
--- a/Content.Server/Atmos/Components/MapAtmosphereComponent.cs
+++ b/Content.Server/Atmos/Components/MapAtmosphereComponent.cs
@@ -1,3 +1,4 @@
+using Content.Shared.Atmos;
using Content.Shared.Atmos.Components;
using Content.Shared.Atmos.EntitySystems;
diff --git a/Content.Server/Atmos/EntitySystems/AirtightSystem.cs b/Content.Server/Atmos/EntitySystems/AirtightSystem.cs
index 5a9134e3b4..cd07da7112 100644
--- a/Content.Server/Atmos/EntitySystems/AirtightSystem.cs
+++ b/Content.Server/Atmos/EntitySystems/AirtightSystem.cs
@@ -36,7 +36,7 @@ namespace Content.Server.Atmos.EntitySystems
airtight.Comp.CurrentAirBlockedDirection =
(int) Rotate((AtmosDirection) airtight.Comp.InitialAirBlockedDirection, xform.LocalRotation);
UpdatePosition(airtight, xform);
- var airtightEv = new AirtightChanged(airtight, airtight, default);
+ var airtightEv = new AirtightChanged(airtight, airtight, false, default);
RaiseLocalEvent(airtight, ref airtightEv, true);
}
@@ -64,7 +64,7 @@ namespace Content.Server.Atmos.EntitySystems
airtight.LastPosition = (gridId.Value, tilePos);
InvalidatePosition(gridId.Value, tilePos);
- var airtightEv = new AirtightChanged(uid, airtight, (gridId.Value, tilePos));
+ var airtightEv = new AirtightChanged(uid, airtight, false, (gridId.Value, tilePos));
RaiseLocalEvent(uid, ref airtightEv, true);
}
@@ -76,7 +76,7 @@ namespace Content.Server.Atmos.EntitySystems
airtight.LastPosition = (gridId, args.TilePos);
InvalidatePosition(gridId, args.TilePos);
- var airtightEv = new AirtightChanged(uid, airtight, (gridId, args.TilePos));
+ var airtightEv = new AirtightChanged(uid, airtight, false, (gridId, args.TilePos));
RaiseLocalEvent(uid, ref airtightEv, true);
}
}
@@ -87,7 +87,7 @@ namespace Content.Server.Atmos.EntitySystems
airtight.CurrentAirBlockedDirection = (int) Rotate((AtmosDirection)airtight.InitialAirBlockedDirection, ev.NewRotation);
var pos = airtight.LastPosition;
UpdatePosition(ent, ev.Component);
- var airtightEv = new AirtightChanged(owner, airtight, pos);
+ var airtightEv = new AirtightChanged(owner, airtight, false, pos);
RaiseLocalEvent(owner, ref airtightEv, true);
}
@@ -102,7 +102,7 @@ namespace Content.Server.Atmos.EntitySystems
var pos = airtight.Comp.LastPosition;
airtight.Comp.AirBlocked = airblocked;
UpdatePosition(airtight, xform);
- var airtightEv = new AirtightChanged(airtight, airtight, pos);
+ var airtightEv = new AirtightChanged(airtight, airtight, true, pos);
RaiseLocalEvent(airtight, ref airtightEv, true);
}
@@ -149,6 +149,13 @@ namespace Content.Server.Atmos.EntitySystems
}
}
+ ///
+ /// Raised upon the airtight status being changed via anchoring, movement, etc.
+ ///
+ ///
+ ///
+ /// Whether the changed
+ ///
[ByRefEvent]
- public readonly record struct AirtightChanged(EntityUid Entity, AirtightComponent Airtight, (EntityUid Grid, Vector2i Tile) Position);
+ public readonly record struct AirtightChanged(EntityUid Entity, AirtightComponent Airtight, bool AirBlockedChanged, (EntityUid Grid, Vector2i Tile) Position);
}
diff --git a/Content.Server/Atmos/EntitySystems/AtmosExposedSystem.cs b/Content.Server/Atmos/EntitySystems/AtmosExposedSystem.cs
index 9590b9aa54..39469e993f 100644
--- a/Content.Server/Atmos/EntitySystems/AtmosExposedSystem.cs
+++ b/Content.Server/Atmos/EntitySystems/AtmosExposedSystem.cs
@@ -1,3 +1,4 @@
+using Content.Shared.Atmos;
using Robust.Shared.Map;
namespace Content.Server.Atmos.EntitySystems
diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs
index 614d550c2f..df31db6ba0 100644
--- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs
+++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs
@@ -1,10 +1,10 @@
using System.Linq;
using Content.Server.Atmos.Components;
using Content.Server.Atmos.Piping.Components;
-using Content.Server.Atmos.Reactions;
using Content.Server.NodeContainer.NodeGroups;
using Content.Shared.Atmos;
using Content.Shared.Atmos.Components;
+using Content.Shared.Atmos.Reactions;
using Robust.Shared.Map.Components;
using Robust.Shared.Utility;
diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs
index f8ee4f4192..70c4639e48 100644
--- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs
+++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs
@@ -2,6 +2,7 @@ using System.Linq;
using System.Runtime.CompilerServices;
using Content.Server.Atmos.Reactions;
using Content.Shared.Atmos;
+using Content.Shared.Atmos.Reactions;
using Robust.Shared.Prototypes;
using DependencyAttribute = Robust.Shared.IoC.DependencyAttribute;
diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.GridAtmosphere.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.GridAtmosphere.cs
index 4b9ef49a40..3830745f68 100644
--- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.GridAtmosphere.cs
+++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.GridAtmosphere.cs
@@ -2,6 +2,7 @@ using Content.Server.Atmos.Components;
using Content.Server.Atmos.Reactions;
using Content.Shared.Atmos;
using Content.Shared.Atmos.Components;
+using Content.Shared.Atmos.Reactions;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Utility;
diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs
index 7163b4cd44..db95223733 100644
--- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs
+++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs
@@ -2,6 +2,7 @@ using Content.Server.Atmos.Components;
using Content.Server.Atmos.Reactions;
using Content.Shared.Atmos;
using Content.Shared.Atmos.Components;
+using Content.Shared.Atmos.Reactions;
using Content.Shared.Audio;
using Content.Shared.Database;
using Robust.Shared.Audio;
diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Map.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Map.cs
index 25b3b801f7..4b77d9c70d 100644
--- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Map.cs
+++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Map.cs
@@ -1,4 +1,5 @@
using Content.Server.Atmos.Components;
+using Content.Shared.Atmos;
using Content.Shared.Atmos.Components;
using Robust.Shared.GameStates;
using Robust.Shared.Map.Components;
diff --git a/Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs b/Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs
index 15e1dde4ec..b42f362629 100644
--- a/Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs
+++ b/Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs
@@ -95,9 +95,9 @@ namespace Content.Server.Atmos.EntitySystems
component.Enabled = true;
Dirty(uid, component);
UpdateAppearance(uid, component);
- if (!HasComp(uid))
- AddComp(uid);
+ EnsureComp(uid);
UpdateAnalyzer(uid, component);
+ OpenUserInterface(uid, user, component);
}
///
diff --git a/Content.Server/Atmos/IGasMixtureHolder.cs b/Content.Server/Atmos/IGasMixtureHolder.cs
index 96efa6b983..65d7ba69a7 100644
--- a/Content.Server/Atmos/IGasMixtureHolder.cs
+++ b/Content.Server/Atmos/IGasMixtureHolder.cs
@@ -1,4 +1,6 @@
-namespace Content.Server.Atmos
+using Content.Shared.Atmos;
+
+namespace Content.Server.Atmos
{
public interface IGasMixtureHolder
{
diff --git a/Content.Server/Atmos/IGasReactionEffect.cs b/Content.Server/Atmos/IGasReactionEffect.cs
index bd229694bb..9fc9231908 100644
--- a/Content.Server/Atmos/IGasReactionEffect.cs
+++ b/Content.Server/Atmos/IGasReactionEffect.cs
@@ -1,5 +1,6 @@
using Content.Server.Atmos.EntitySystems;
-using Content.Server.Atmos.Reactions;
+using Content.Shared.Atmos;
+using Content.Shared.Atmos.Reactions;
namespace Content.Server.Atmos
{
diff --git a/Content.Server/Atmos/Piping/Binary/Components/GasPortComponent.cs b/Content.Server/Atmos/Piping/Binary/Components/GasPortComponent.cs
index fb7ee6d5cf..315362383c 100644
--- a/Content.Server/Atmos/Piping/Binary/Components/GasPortComponent.cs
+++ b/Content.Server/Atmos/Piping/Binary/Components/GasPortComponent.cs
@@ -1,3 +1,5 @@
+using Content.Shared.Atmos;
+
namespace Content.Server.Atmos.Piping.Binary.Components
{
[RegisterComponent]
diff --git a/Content.Server/Atmos/Portable/PortableScrubberSystem.cs b/Content.Server/Atmos/Portable/PortableScrubberSystem.cs
index 91ee588057..bc5db2e22c 100644
--- a/Content.Server/Atmos/Portable/PortableScrubberSystem.cs
+++ b/Content.Server/Atmos/Portable/PortableScrubberSystem.cs
@@ -13,6 +13,7 @@ using Content.Server.NodeContainer.NodeGroups;
using Content.Server.Audio;
using Content.Server.Administration.Logs;
using Content.Server.NodeContainer.EntitySystems;
+using Content.Shared.Atmos;
using Content.Shared.Database;
namespace Content.Server.Atmos.Portable
diff --git a/Content.Server/Atmos/Reactions/AmmoniaOxygenReaction.cs b/Content.Server/Atmos/Reactions/AmmoniaOxygenReaction.cs
index 197034ce54..2c071afab1 100644
--- a/Content.Server/Atmos/Reactions/AmmoniaOxygenReaction.cs
+++ b/Content.Server/Atmos/Reactions/AmmoniaOxygenReaction.cs
@@ -1,5 +1,6 @@
using Content.Server.Atmos.EntitySystems;
using Content.Shared.Atmos;
+using Content.Shared.Atmos.Reactions;
using JetBrains.Annotations;
namespace Content.Server.Atmos.Reactions;
diff --git a/Content.Server/Atmos/Reactions/FrezonCoolantReaction.cs b/Content.Server/Atmos/Reactions/FrezonCoolantReaction.cs
index 051ee8202d..475c149cf3 100644
--- a/Content.Server/Atmos/Reactions/FrezonCoolantReaction.cs
+++ b/Content.Server/Atmos/Reactions/FrezonCoolantReaction.cs
@@ -1,5 +1,6 @@
using Content.Server.Atmos.EntitySystems;
using Content.Shared.Atmos;
+using Content.Shared.Atmos.Reactions;
using JetBrains.Annotations;
namespace Content.Server.Atmos.Reactions;
diff --git a/Content.Server/Atmos/Reactions/FrezonProductionReaction.cs b/Content.Server/Atmos/Reactions/FrezonProductionReaction.cs
index 4ffd9c2f5b..e3d3ece6b6 100644
--- a/Content.Server/Atmos/Reactions/FrezonProductionReaction.cs
+++ b/Content.Server/Atmos/Reactions/FrezonProductionReaction.cs
@@ -1,5 +1,6 @@
using Content.Server.Atmos.EntitySystems;
using Content.Shared.Atmos;
+using Content.Shared.Atmos.Reactions;
using JetBrains.Annotations;
namespace Content.Server.Atmos.Reactions;
diff --git a/Content.Server/Atmos/Reactions/GasReactionPrototype.cs b/Content.Server/Atmos/Reactions/GasReactionPrototype.cs
index 0ee29de3bf..48a113bb9a 100644
--- a/Content.Server/Atmos/Reactions/GasReactionPrototype.cs
+++ b/Content.Server/Atmos/Reactions/GasReactionPrototype.cs
@@ -1,22 +1,10 @@
using Content.Server.Atmos.EntitySystems;
using Content.Shared.Atmos;
+using Content.Shared.Atmos.Reactions;
using Robust.Shared.Prototypes;
namespace Content.Server.Atmos.Reactions
{
- [Flags]
- public enum ReactionResult : byte
- {
- NoReaction = 0,
- Reacting = 1,
- StopReactions = 2,
- }
-
- public enum GasReaction : byte
- {
- Fire = 0,
- }
-
[Prototype("gasReaction")]
public sealed partial class GasReactionPrototype : IPrototype
{
diff --git a/Content.Server/Atmos/Reactions/N2ODecompositionReaction.cs b/Content.Server/Atmos/Reactions/N2ODecompositionReaction.cs
index 7fce663dc3..367c0eb7b9 100644
--- a/Content.Server/Atmos/Reactions/N2ODecompositionReaction.cs
+++ b/Content.Server/Atmos/Reactions/N2ODecompositionReaction.cs
@@ -1,5 +1,6 @@
using Content.Server.Atmos.EntitySystems;
using Content.Shared.Atmos;
+using Content.Shared.Atmos.Reactions;
using JetBrains.Annotations;
namespace Content.Server.Atmos.Reactions;
diff --git a/Content.Server/Atmos/Reactions/PlasmaFireReaction.cs b/Content.Server/Atmos/Reactions/PlasmaFireReaction.cs
index e7ab7835fd..98d567d4ed 100644
--- a/Content.Server/Atmos/Reactions/PlasmaFireReaction.cs
+++ b/Content.Server/Atmos/Reactions/PlasmaFireReaction.cs
@@ -1,5 +1,6 @@
using Content.Server.Atmos.EntitySystems;
using Content.Shared.Atmos;
+using Content.Shared.Atmos.Reactions;
using JetBrains.Annotations;
namespace Content.Server.Atmos.Reactions
diff --git a/Content.Server/Atmos/Reactions/TritiumFireReaction.cs b/Content.Server/Atmos/Reactions/TritiumFireReaction.cs
index 7103859a90..3ad0a4b04d 100644
--- a/Content.Server/Atmos/Reactions/TritiumFireReaction.cs
+++ b/Content.Server/Atmos/Reactions/TritiumFireReaction.cs
@@ -1,5 +1,6 @@
using Content.Server.Atmos.EntitySystems;
using Content.Shared.Atmos;
+using Content.Shared.Atmos.Reactions;
using JetBrains.Annotations;
namespace Content.Server.Atmos.Reactions
diff --git a/Content.Server/Atmos/Reactions/WaterVaporReaction.cs b/Content.Server/Atmos/Reactions/WaterVaporReaction.cs
index 8db8fdbd66..e06c4b75ff 100644
--- a/Content.Server/Atmos/Reactions/WaterVaporReaction.cs
+++ b/Content.Server/Atmos/Reactions/WaterVaporReaction.cs
@@ -1,5 +1,7 @@
using Content.Server.Atmos.EntitySystems;
using Content.Server.Fluids.EntitySystems;
+using Content.Shared.Atmos;
+using Content.Shared.Atmos.Reactions;
using Content.Shared.Chemistry.Components;
using Content.Shared.FixedPoint;
using Content.Shared.Maps;
diff --git a/Content.Server/Atmos/Serialization/TileAtmosCollectionSerializer.cs b/Content.Server/Atmos/Serialization/TileAtmosCollectionSerializer.cs
index 00be83e86d..5b30d65e48 100644
--- a/Content.Server/Atmos/Serialization/TileAtmosCollectionSerializer.cs
+++ b/Content.Server/Atmos/Serialization/TileAtmosCollectionSerializer.cs
@@ -1,4 +1,5 @@
using System.Globalization;
+using Content.Shared.Atmos;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Markdown;
diff --git a/Content.Server/Atmos/TileMixtureEnumerator.cs b/Content.Server/Atmos/TileMixtureEnumerator.cs
index 20440032da..5601615f50 100644
--- a/Content.Server/Atmos/TileMixtureEnumerator.cs
+++ b/Content.Server/Atmos/TileMixtureEnumerator.cs
@@ -1,4 +1,5 @@
using System.Diagnostics.CodeAnalysis;
+using Content.Shared.Atmos;
namespace Content.Server.Atmos;
diff --git a/Content.Server/Botany/Systems/PlantHolderSystem.cs b/Content.Server/Botany/Systems/PlantHolderSystem.cs
index 721536a7c0..c8842e1493 100644
--- a/Content.Server/Botany/Systems/PlantHolderSystem.cs
+++ b/Content.Server/Botany/Systems/PlantHolderSystem.cs
@@ -6,6 +6,7 @@ using Content.Server.Fluids.Components;
using Content.Server.Ghost.Roles.Components;
using Content.Server.Kitchen.Components;
using Content.Server.Popups;
+using Content.Shared.Atmos;
using Content.Shared.Botany;
using Content.Shared.Burial.Components;
using Content.Shared.Chemistry.Reagent;
diff --git a/Content.Server/Destructible/Thresholds/Behaviors/SpawnGasBehavior.cs b/Content.Server/Destructible/Thresholds/Behaviors/SpawnGasBehavior.cs
index fec93a87f4..81fb07ecfc 100644
--- a/Content.Server/Destructible/Thresholds/Behaviors/SpawnGasBehavior.cs
+++ b/Content.Server/Destructible/Thresholds/Behaviors/SpawnGasBehavior.cs
@@ -1,4 +1,5 @@
using Content.Server.Atmos;
+using Content.Shared.Atmos;
using JetBrains.Annotations;
namespace Content.Server.Destructible.Thresholds.Behaviors;
diff --git a/Content.Server/Disposal/Unit/Components/DisposalHolderComponent.cs b/Content.Server/Disposal/Unit/Components/DisposalHolderComponent.cs
index 3df2182b41..690b33968b 100644
--- a/Content.Server/Disposal/Unit/Components/DisposalHolderComponent.cs
+++ b/Content.Server/Disposal/Unit/Components/DisposalHolderComponent.cs
@@ -1,5 +1,6 @@
using Content.Server.Atmos;
using Content.Server.Disposal.Tube.Components;
+using Content.Shared.Atmos;
using Robust.Shared.Containers;
namespace Content.Server.Disposal.Unit.Components
diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.CVars.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.CVars.cs
index 1f03109333..3332d3a4f5 100644
--- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.CVars.cs
+++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.CVars.cs
@@ -11,7 +11,8 @@ public sealed partial class ExplosionSystem : EntitySystem
public int ThrowLimit { get; private set; }
public bool SleepNodeSys { get; private set; }
public bool IncrementalTileBreaking { get; private set; }
- public int SingleTickAreaLimit {get; private set; }
+ public int SingleTickAreaLimit { get; private set; }
+ public bool CanCreateVacuum { get; private set; }
private void SubscribeCvars()
{
@@ -23,5 +24,6 @@ public sealed partial class ExplosionSystem : EntitySystem
Subs.CVar(_cfg, CCVars.ExplosionMaxProcessingTime, value => MaxProcessingTime = value, true);
Subs.CVar(_cfg, CCVars.ExplosionIncrementalTileBreaking, value => IncrementalTileBreaking = value, true);
Subs.CVar(_cfg, CCVars.ExplosionSingleTickAreaLimit, value => SingleTickAreaLimit = value, true);
+ Subs.CVar(_cfg, CCVars.ExplosionCanCreateVacuum, value => CanCreateVacuum = value, true);
}
}
diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs
index 6e100fe656..a93157a175 100644
--- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs
+++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs
@@ -1,4 +1,5 @@
using System.Numerics;
+using Content.Server.Atmos.EntitySystems;
using Content.Shared.CCVar;
using Content.Shared.Damage;
using Content.Shared.Explosion;
@@ -16,7 +17,6 @@ using Robust.Shared.Random;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
using TimedDespawnComponent = Robust.Shared.Spawners.TimedDespawnComponent;
-using Content.Server.Atmos.EntitySystems;
namespace Content.Server.Explosion.EntitySystems;
@@ -490,7 +490,9 @@ public sealed partial class ExplosionSystem
if (_tileDefinitionManager[tileRef.Tile.TypeId] is not ContentTileDefinition tileDef)
return;
- if (tileDef.MapAtmosphere)
+ if (!CanCreateVacuum)
+ canCreateVacuum = false;
+ else if (tileDef.MapAtmosphere)
canCreateVacuum = true; // is already a vacuum.
int tileBreakages = 0;
diff --git a/Content.Server/Fluids/EntitySystems/SpraySystem.cs b/Content.Server/Fluids/EntitySystems/SpraySystem.cs
index 40f19aff2b..5499070738 100644
--- a/Content.Server/Fluids/EntitySystems/SpraySystem.cs
+++ b/Content.Server/Fluids/EntitySystems/SpraySystem.cs
@@ -144,7 +144,7 @@ public sealed class SpraySystem : EntitySystem
_audio.PlayPvs(entity.Comp.SpraySound, entity, entity.Comp.SpraySound.Params.WithVariation(0.125f));
- _useDelay.SetLength((entity, useDelay), TimeSpan.FromSeconds(cooldownTime));
+ _useDelay.SetLength(entity.Owner, TimeSpan.FromSeconds(cooldownTime));
_useDelay.TryResetDelay((entity, useDelay));
}
}
diff --git a/Content.Server/Ghost/GhostSystem.cs b/Content.Server/Ghost/GhostSystem.cs
index c0e753c4c5..0be93d2054 100644
--- a/Content.Server/Ghost/GhostSystem.cs
+++ b/Content.Server/Ghost/GhostSystem.cs
@@ -43,10 +43,16 @@ namespace Content.Server.Ghost
[Dependency] private readonly TransformSystem _transformSystem = default!;
[Dependency] private readonly VisibilitySystem _visibilitySystem = default!;
+ private EntityQuery _ghostQuery;
+ private EntityQuery _physicsQuery;
+
public override void Initialize()
{
base.Initialize();
+ _ghostQuery = GetEntityQuery();
+ _physicsQuery = GetEntityQuery();
+
SubscribeLocalEvent(OnGhostStartup);
SubscribeLocalEvent(OnMapInit);
SubscribeLocalEvent(OnGhostShutdown);
@@ -62,6 +68,7 @@ namespace Content.Server.Ghost
SubscribeNetworkEvent(OnGhostWarpsRequest);
SubscribeNetworkEvent(OnGhostReturnToBodyRequest);
SubscribeNetworkEvent(OnGhostWarpToTargetRequest);
+ SubscribeNetworkEvent(OnGhostnadoRequest);
SubscribeLocalEvent(OnActionPerform);
SubscribeLocalEvent(OnGhostHearingAction);
@@ -241,7 +248,7 @@ namespace Content.Server.Ghost
private void OnGhostReturnToBodyRequest(GhostReturnToBodyRequest msg, EntitySessionEventArgs args)
{
if (args.SenderSession.AttachedEntity is not {Valid: true} attached
- || !TryComp(attached, out GhostComponent? ghost)
+ || !_ghostQuery.TryComp(attached, out var ghost)
|| !ghost.CanReturnToBody
|| !TryComp(attached, out ActorComponent? actor))
{
@@ -257,7 +264,7 @@ namespace Content.Server.Ghost
private void OnGhostWarpsRequest(GhostWarpsRequestEvent msg, EntitySessionEventArgs args)
{
if (args.SenderSession.AttachedEntity is not {Valid: true} entity
- || !HasComp(entity))
+ || !_ghostQuery.HasComp(entity))
{
Log.Warning($"User {args.SenderSession.Name} sent a {nameof(GhostWarpsRequestEvent)} without being a ghost.");
return;
@@ -270,7 +277,7 @@ namespace Content.Server.Ghost
private void OnGhostWarpToTargetRequest(GhostWarpToTargetRequestEvent msg, EntitySessionEventArgs args)
{
if (args.SenderSession.AttachedEntity is not {Valid: true} attached
- || !TryComp(attached, out GhostComponent? _))
+ || !_ghostQuery.HasComp(attached))
{
Log.Warning($"User {args.SenderSession.Name} tried to warp to {msg.Target} without being a ghost.");
return;
@@ -284,17 +291,37 @@ namespace Content.Server.Ghost
return;
}
- if ((TryComp(target, out WarpPointComponent? warp) && warp.Follow) || HasComp(target))
+ WarpTo(attached, target);
+ }
+
+ private void OnGhostnadoRequest(GhostnadoRequestEvent msg, EntitySessionEventArgs args)
+ {
+ if (args.SenderSession.AttachedEntity is not {} uid
+ || !_ghostQuery.HasComp(uid))
{
- _followerSystem.StartFollowingEntity(attached, target);
+ Log.Warning($"User {args.SenderSession.Name} tried to ghostnado without being a ghost.");
return;
}
- var xform = Transform(attached);
- _transformSystem.SetCoordinates(attached, xform, Transform(target).Coordinates);
- _transformSystem.AttachToGridOrMap(attached, xform);
- if (TryComp(attached, out PhysicsComponent? physics))
- _physics.SetLinearVelocity(attached, Vector2.Zero, body: physics);
+ if (_followerSystem.GetMostFollowed() is not {} target)
+ return;
+
+ WarpTo(uid, target);
+ }
+
+ private void WarpTo(EntityUid uid, EntityUid target)
+ {
+ if ((TryComp(target, out WarpPointComponent? warp) && warp.Follow) || HasComp(target))
+ {
+ _followerSystem.StartFollowingEntity(uid, target);
+ return;
+ }
+
+ var xform = Transform(uid);
+ _transformSystem.SetCoordinates(uid, xform, Transform(target).Coordinates);
+ _transformSystem.AttachToGridOrMap(uid, xform);
+ if (_physicsQuery.TryComp(uid, out var physics))
+ _physics.SetLinearVelocity(uid, Vector2.Zero, body: physics);
}
private IEnumerable GetLocationWarps()
diff --git a/Content.Server/Hands/Systems/HandsSystem.cs b/Content.Server/Hands/Systems/HandsSystem.cs
index e7527e2c76..4c6b80bd98 100644
--- a/Content.Server/Hands/Systems/HandsSystem.cs
+++ b/Content.Server/Hands/Systems/HandsSystem.cs
@@ -20,6 +20,7 @@ using Robust.Shared.GameStates;
using Robust.Shared.Input.Binding;
using Robust.Shared.Map;
using Robust.Shared.Player;
+using Robust.Shared.Random;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
@@ -28,6 +29,7 @@ namespace Content.Server.Hands.Systems
public sealed class HandsSystem : SharedHandsSystem
{
[Dependency] private readonly IGameTiming _timing = default!;
+ [Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly StackSystem _stackSystem = default!;
[Dependency] private readonly VirtualItemSystem _virtualItemSystem = default!;
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
@@ -91,7 +93,8 @@ namespace Content.Server.Hands.Systems
if (TryComp(uid, out PullerComponent? puller) && TryComp(puller.Pulling, out PullableComponent? pullable))
_pullingSystem.TryStopPull(puller.Pulling.Value, pullable);
- if (!_handsSystem.TryDrop(uid, component.ActiveHand!, null, checkActionBlocker: false))
+ var offsetRandomCoordinates = _transformSystem.GetMoverCoordinates(args.Target).Offset(_random.NextVector2(1f, 1.5f));
+ if (!ThrowHeldItem(args.Target, offsetRandomCoordinates))
return;
args.PopupPrefix = "disarm-action-";
diff --git a/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs b/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs
index fa5c5dad2a..8938aa8b1d 100644
--- a/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs
+++ b/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs
@@ -271,6 +271,9 @@ namespace Content.Server.Kitchen.EntitySystems
private void OnContentUpdate(EntityUid uid, MicrowaveComponent component, ContainerModifiedMessage args) // For some reason ContainerModifiedMessage just can't be used at all with Entity. TODO: replace with Entity syntax once that's possible
{
+ if (component.Storage != args.Container)
+ return;
+
UpdateUserInterfaceState(uid, component);
}
diff --git a/Content.Server/Lathe/LatheSystem.cs b/Content.Server/Lathe/LatheSystem.cs
index f56737a5a5..2b3b810fba 100644
--- a/Content.Server/Lathe/LatheSystem.cs
+++ b/Content.Server/Lathe/LatheSystem.cs
@@ -8,6 +8,7 @@ using Content.Server.Materials;
using Content.Server.Power.Components;
using Content.Server.Power.EntitySystems;
using Content.Server.Stack;
+using Content.Shared.Atmos;
using Content.Shared.UserInterface;
using Content.Shared.Database;
using Content.Shared.Emag.Components;
diff --git a/Content.Server/Mech/Components/MechAirComponent.cs b/Content.Server/Mech/Components/MechAirComponent.cs
index c533b3d834..d312e1b739 100644
--- a/Content.Server/Mech/Components/MechAirComponent.cs
+++ b/Content.Server/Mech/Components/MechAirComponent.cs
@@ -1,4 +1,5 @@
using Content.Server.Atmos;
+using Content.Shared.Atmos;
namespace Content.Server.Mech.Components;
diff --git a/Content.Server/Medical/CryoPodSystem.cs b/Content.Server/Medical/CryoPodSystem.cs
index 71921f44fd..8d54fc6dd9 100644
--- a/Content.Server/Medical/CryoPodSystem.cs
+++ b/Content.Server/Medical/CryoPodSystem.cs
@@ -13,6 +13,7 @@ using Content.Server.NodeContainer.NodeGroups;
using Content.Server.NodeContainer.Nodes;
using Content.Server.Power.Components;
using Content.Server.Temperature.Components;
+using Content.Shared.Atmos;
using Content.Shared.UserInterface;
using Content.Shared.Chemistry;
using Content.Shared.Chemistry.Components;
diff --git a/Content.Server/Nutrition/EntitySystems/SmokingSystem.Vape.cs b/Content.Server/Nutrition/EntitySystems/SmokingSystem.Vape.cs
index fb56dffac9..f7650f599b 100644
--- a/Content.Server/Nutrition/EntitySystems/SmokingSystem.Vape.cs
+++ b/Content.Server/Nutrition/EntitySystems/SmokingSystem.Vape.cs
@@ -13,6 +13,7 @@ using Content.Shared.IdentityManagement;
using Content.Shared.Interaction;
using Content.Shared.Nutrition;
using System.Threading;
+using Content.Shared.Atmos;
///
/// System for vapes
diff --git a/Content.Server/Pinpointer/NavMapSystem.cs b/Content.Server/Pinpointer/NavMapSystem.cs
index 0aa6ab1908..dba964753f 100644
--- a/Content.Server/Pinpointer/NavMapSystem.cs
+++ b/Content.Server/Pinpointer/NavMapSystem.cs
@@ -12,7 +12,6 @@ using JetBrains.Annotations;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Timing;
-using Robust.Shared.Utility;
using System.Diagnostics.CodeAnalysis;
namespace Content.Server.Pinpointer;
@@ -28,14 +27,27 @@ public sealed partial class NavMapSystem : SharedNavMapSystem
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
+ [Dependency] private readonly ITileDefinitionManager _tileDefManager = default!;
public const float CloseDistance = 15f;
public const float FarDistance = 30f;
+ private EntityQuery _airtightQuery;
+ private EntityQuery _gridQuery;
+ private EntityQuery _navQuery;
+
public override void Initialize()
{
base.Initialize();
+ var categories = Enum.GetNames(typeof(NavMapChunkType)).Length - 1; // -1 due to "Invalid" entry.
+ if (Categories != categories)
+ throw new Exception($"{nameof(Categories)} must be equal to the number of chunk types");
+
+ _airtightQuery = GetEntityQuery();
+ _gridQuery = GetEntityQuery();
+ _navQuery = GetEntityQuery();
+
// Initialization events
SubscribeLocalEvent(OnStationInit);
@@ -43,8 +55,7 @@ public sealed partial class NavMapSystem : SharedNavMapSystem
SubscribeLocalEvent(OnNavMapSplit);
SubscribeLocalEvent(OnTileChanged);
- // Airtight structure change event
- SubscribeLocalEvent(OnAirtightChanged);
+ SubscribeLocalEvent(OnAirtightChange);
// Beacon events
SubscribeLocalEvent(OnNavMapBeaconMapInit);
@@ -54,82 +65,96 @@ public sealed partial class NavMapSystem : SharedNavMapSystem
SubscribeLocalEvent(OnConfigurableExamined);
}
- #region: Initialization event handling
private void OnStationInit(StationGridAddedEvent ev)
{
var comp = EnsureComp(ev.GridId);
RefreshGrid(ev.GridId, comp, Comp(ev.GridId));
}
- #endregion
-
#region: Grid change event handling
private void OnNavMapSplit(ref GridSplitEvent args)
{
- if (!TryComp(args.Grid, out NavMapComponent? comp))
+ if (!_navQuery.TryComp(args.Grid, out var comp))
return;
- var gridQuery = GetEntityQuery();
-
foreach (var grid in args.NewGrids)
{
var newComp = EnsureComp(grid);
- RefreshGrid(grid, newComp, gridQuery.GetComponent(grid));
+ RefreshGrid(grid, newComp, _gridQuery.GetComponent(grid));
}
- RefreshGrid(args.Grid, comp, gridQuery.GetComponent(args.Grid));
+ RefreshGrid(args.Grid, comp, _gridQuery.GetComponent(args.Grid));
+ }
+
+ private NavMapChunk EnsureChunk(NavMapComponent component, Vector2i origin)
+ {
+ if (!component.Chunks.TryGetValue(origin, out var chunk))
+ {
+ chunk = new(origin);
+ component.Chunks[origin] = chunk;
+ }
+
+ return chunk;
}
private void OnTileChanged(ref TileChangedEvent ev)
{
- if (!TryComp(ev.NewTile.GridUid, out var navMap))
+ if (!ev.EmptyChanged || !_navQuery.TryComp(ev.NewTile.GridUid, out var navMap))
return;
var tile = ev.NewTile.GridIndices;
var chunkOrigin = SharedMapSystem.GetChunkIndices(tile, ChunkSize);
- if (!navMap.Chunks.TryGetValue((NavMapChunkType.Floor, chunkOrigin), out var chunk))
- chunk = new(chunkOrigin);
+ var chunk = EnsureChunk(navMap, chunkOrigin);
// This could be easily replaced in the future to accommodate diagonal tiles
- if (ev.NewTile.IsSpace())
- chunk = UnsetAllEdgesForChunkTile(chunk, tile);
+ var relative = SharedMapSystem.GetChunkRelative(tile, ChunkSize);
+ ref var tileData = ref chunk.TileData[GetTileIndex(relative)];
- else
- chunk = SetAllEdgesForChunkTile(chunk, tile);
-
- chunk.LastUpdate = _gameTiming.CurTick;
- navMap.Chunks[(NavMapChunkType.Floor, chunkOrigin)] = chunk;
-
- Dirty(ev.NewTile.GridUid, navMap);
- }
-
- private void OnAirtightChanged(ref AirtightChanged ev)
- {
- var gridUid = ev.Position.Grid;
-
- if (!TryComp(gridUid, out var navMap) ||
- !TryComp(gridUid, out var mapGrid))
- return;
-
- // Refresh the affected tile
- var tile = ev.Position.Tile;
- var chunkOrigin = SharedMapSystem.GetChunkIndices(tile, ChunkSize);
-
- RefreshTileEntityContents(gridUid, navMap, mapGrid, chunkOrigin, tile);
-
- // Update potentially affected chunks
- foreach (var category in EntityChunkTypes)
+ if (ev.NewTile.IsSpace(_tileDefManager))
{
- if (!navMap.Chunks.TryGetValue((category, chunkOrigin), out var chunk))
- continue;
-
- chunk.LastUpdate = _gameTiming.CurTick;
- navMap.Chunks[(category, chunkOrigin)] = chunk;
+ tileData = 0;
+ if (PruneEmpty((ev.NewTile.GridUid, navMap), chunk))
+ return;
+ }
+ else
+ {
+ tileData = FloorMask;
}
- Dirty(gridUid, navMap);
+ DirtyChunk((ev.NewTile.GridUid, navMap), chunk);
+ }
+
+ private void DirtyChunk(Entity entity, NavMapChunk chunk)
+ {
+ if (chunk.LastUpdate == _gameTiming.CurTick)
+ return;
+
+ chunk.LastUpdate = _gameTiming.CurTick;
+ Dirty(entity);
+ }
+
+ private void OnAirtightChange(ref AirtightChanged args)
+ {
+ if (args.AirBlockedChanged)
+ return;
+
+ var gridUid = args.Position.Grid;
+
+ if (!_navQuery.TryComp(gridUid, out var navMap) ||
+ !_gridQuery.TryComp(gridUid, out var mapGrid))
+ {
+ return;
+ }
+
+ var chunkOrigin = SharedMapSystem.GetChunkIndices(args.Position.Tile, ChunkSize);
+ var (newValue, chunk) = RefreshTileEntityContents(gridUid, navMap, mapGrid, chunkOrigin, args.Position.Tile, setFloor: false);
+
+ if (newValue == 0 && PruneEmpty((gridUid, navMap), chunk))
+ return;
+
+ DirtyChunk((gridUid, navMap), chunk);
}
#endregion
@@ -220,76 +245,70 @@ public sealed partial class NavMapSystem : SharedNavMapSystem
var tile = tileRef.GridIndices;
var chunkOrigin = SharedMapSystem.GetChunkIndices(tile, ChunkSize);
- if (!component.Chunks.TryGetValue((NavMapChunkType.Floor, chunkOrigin), out var chunk))
- chunk = new(chunkOrigin);
-
+ var chunk = EnsureChunk(component, chunkOrigin);
chunk.LastUpdate = _gameTiming.CurTick;
-
- // Refresh the floor tile
- component.Chunks[(NavMapChunkType.Floor, chunkOrigin)] = SetAllEdgesForChunkTile(chunk, tile);
-
- // Refresh the contents of the tile
- RefreshTileEntityContents(uid, component, mapGrid, chunkOrigin, tile);
+ RefreshTileEntityContents(uid, component, mapGrid, chunkOrigin, tile, setFloor: true);
}
Dirty(uid, component);
}
- private void RefreshTileEntityContents(EntityUid uid, NavMapComponent component, MapGridComponent mapGrid, Vector2i chunkOrigin, Vector2i tile)
+ private (int NewVal, NavMapChunk Chunk) RefreshTileEntityContents(EntityUid uid,
+ NavMapComponent component,
+ MapGridComponent mapGrid,
+ Vector2i chunkOrigin,
+ Vector2i tile,
+ bool setFloor)
{
var relative = SharedMapSystem.GetChunkRelative(tile, ChunkSize);
- var flag = (ushort) GetFlag(relative);
- var invFlag = (ushort) ~flag;
+ var chunk = EnsureChunk(component, chunkOrigin);
+ ref var tileData = ref chunk.TileData[GetTileIndex(relative)];
- // Clear stale data from the tile across all entity associated chunks
- foreach (var category in EntityChunkTypes)
- {
- if (!component.Chunks.TryGetValue((category, chunkOrigin), out var chunk))
- chunk = new(chunkOrigin);
+ // Clear all data except for floor bits
+ if (setFloor)
+ tileData = FloorMask;
+ else
+ tileData &= FloorMask;
- foreach (var (direction, _) in chunk.TileData)
- chunk.TileData[direction] &= invFlag;
-
- chunk.LastUpdate = _gameTiming.CurTick;
- component.Chunks[(category, chunkOrigin)] = chunk;
- }
-
- // Update the tile data based on what entities are still anchored to the tile
var enumerator = _mapSystem.GetAnchoredEntitiesEnumerator(uid, mapGrid, tile);
-
while (enumerator.MoveNext(out var ent))
{
- if (!TryComp(ent, out var entAirtight))
+ if (!_airtightQuery.TryComp(ent, out var airtight))
continue;
- var category = GetAssociatedEntityChunkType(ent.Value);
-
- if (!component.Chunks.TryGetValue((category, chunkOrigin), out var chunk))
+ var category = GetEntityType(ent.Value);
+ if (category == NavMapChunkType.Invalid)
continue;
- foreach (var (direction, _) in chunk.TileData)
- {
- if ((direction & entAirtight.AirBlockedDirection) > 0)
- chunk.TileData[direction] |= flag;
- }
-
- chunk.LastUpdate = _gameTiming.CurTick;
- component.Chunks[(category, chunkOrigin)] = chunk;
+ var directions = (int)airtight.AirBlockedDirection;
+ tileData |= directions << (int) category;
}
// Remove walls that intersect with doors (unless they can both physically fit on the same tile)
- if (component.Chunks.TryGetValue((NavMapChunkType.Wall, chunkOrigin), out var wallChunk) &&
- component.Chunks.TryGetValue((NavMapChunkType.Airlock, chunkOrigin), out var airlockChunk))
- {
- foreach (var (direction, _) in wallChunk.TileData)
- {
- var airlockInvFlag = (ushort) ~airlockChunk.TileData[direction];
- wallChunk.TileData[direction] &= airlockInvFlag;
- }
+ // TODO NAVMAP why can this even happen?
+ // Is this for blast-doors or something?
- wallChunk.LastUpdate = _gameTiming.CurTick;
- component.Chunks[(NavMapChunkType.Wall, chunkOrigin)] = wallChunk;
+ // Shift airlock bits over to the wall bits
+ var shiftedAirlockBits = (tileData & AirlockMask) >> ((int) NavMapChunkType.Airlock - (int) NavMapChunkType.Wall);
+
+ // And then mask door bits
+ tileData &= ~shiftedAirlockBits;
+
+ return (tileData, chunk);
+ }
+
+ private bool PruneEmpty(Entity entity, NavMapChunk chunk)
+ {
+ foreach (var val in chunk.TileData)
+ {
+ // TODO NAVMAP SIMD
+ if (val != 0)
+ return false;
}
+
+ entity.Comp.Chunks.Remove(chunk.Origin);
+ Dirty(entity);
+ return true;
}
#endregion
@@ -304,22 +323,15 @@ public sealed partial class NavMapSystem : SharedNavMapSystem
if (xform.GridUid == null)
return;
- if (!TryComp(xform.GridUid, out var navMap))
+ if (!_navQuery.TryComp(xform.GridUid, out var navMap))
return;
- var netEnt = GetNetEntity(uid);
- var oldBeacon = navMap.Beacons.FirstOrNull(x => x.NetEnt == netEnt);
- var changed = false;
+ var meta = MetaData(uid);
+ var changed = navMap.Beacons.Remove(meta.NetEntity);
- if (oldBeacon != null)
+ if (TryCreateNavMapBeaconData(uid, component, xform, meta, out var beaconData))
{
- navMap.Beacons.Remove(oldBeacon.Value);
- changed = true;
- }
-
- if (TryCreateNavMapBeaconData(uid, component, xform, out var beaconData))
- {
- navMap.Beacons.Add(beaconData.Value);
+ navMap.Beacons.Add(meta.NetEntity, beaconData.Value);
changed = true;
}
diff --git a/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingSystem.cs b/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingSystem.cs
index 035b60e4f3..e594e4de26 100644
--- a/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingSystem.cs
+++ b/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingSystem.cs
@@ -1,4 +1,6 @@
using System.Linq;
+using Content.Server.Administration;
+using Content.Server.Administration.Managers;
using Content.Server.Afk;
using Content.Server.Afk.Events;
using Content.Server.GameTicking;
@@ -31,6 +33,7 @@ public sealed class PlayTimeTrackingSystem : EntitySystem
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly MindSystem _minds = default!;
[Dependency] private readonly PlayTimeTrackingManager _tracking = default!;
+ [Dependency] private readonly IAdminManager _adminManager = default!;
public override void Initialize()
{
@@ -47,6 +50,7 @@ public sealed class PlayTimeTrackingSystem : EntitySystem
SubscribeLocalEvent(OnUnAFK);
SubscribeLocalEvent(OnMobStateChanged);
SubscribeLocalEvent(OnPlayerJoinedLobby);
+ _adminManager.OnPermsChanged += AdminPermsChanged;
}
public override void Shutdown()
@@ -54,6 +58,7 @@ public sealed class PlayTimeTrackingSystem : EntitySystem
base.Shutdown();
_tracking.CalcTrackers -= CalcTrackers;
+ _adminManager.OnPermsChanged -= AdminPermsChanged;
}
private void CalcTrackers(ICommonSession player, HashSet trackers)
@@ -61,6 +66,13 @@ public sealed class PlayTimeTrackingSystem : EntitySystem
if (_afk.IsAfk(player))
return;
+ if (_adminManager.IsAdmin(player))
+ {
+ trackers.Add(PlayTimeTrackingShared.TrackerAdmin);
+ trackers.Add(PlayTimeTrackingShared.TrackerOverall);
+ return;
+ }
+
if (!IsPlayerAlive(player))
return;
@@ -131,6 +143,11 @@ public sealed class PlayTimeTrackingSystem : EntitySystem
_tracking.QueueRefreshTrackers(ev.Session);
}
+ private void AdminPermsChanged(AdminPermsChangedEventArgs admin)
+ {
+ _tracking.QueueRefreshTrackers(admin.Player);
+ }
+
private void OnPlayerAttached(PlayerAttachedEvent ev)
{
_tracking.QueueRefreshTrackers(ev.Player);
diff --git a/Content.Server/Power/EntitySystems/PowerMonitoringConsoleSystem.cs b/Content.Server/Power/EntitySystems/PowerMonitoringConsoleSystem.cs
index be1238fd2b..42c84b7f43 100644
--- a/Content.Server/Power/EntitySystems/PowerMonitoringConsoleSystem.cs
+++ b/Content.Server/Power/EntitySystems/PowerMonitoringConsoleSystem.cs
@@ -1,7 +1,5 @@
-using Content.Server.GameTicking.Rules.Components;
using Content.Server.NodeContainer;
using Content.Server.NodeContainer.EntitySystems;
-using Content.Server.NodeContainer.NodeGroups;
using Content.Server.NodeContainer.Nodes;
using Content.Server.Power.Components;
using Content.Server.Power.Nodes;
@@ -13,10 +11,8 @@ using Content.Shared.Power;
using JetBrains.Annotations;
using Robust.Server.GameObjects;
using Robust.Shared.Map.Components;
-using Robust.Shared.Player;
using Robust.Shared.Utility;
using System.Linq;
-using System.Diagnostics.CodeAnalysis;
using Content.Server.GameTicking.Components;
namespace Content.Server.Power.EntitySystems;
@@ -163,7 +159,7 @@ internal sealed partial class PowerMonitoringConsoleSystem : SharedPowerMonitori
allChunks = new();
var tile = _sharedMapSystem.LocalToTile(xform.GridUid.Value, grid, xform.Coordinates);
- var chunkOrigin = SharedMapSystem.GetChunkIndices(tile, SharedNavMapSystem.ChunkSize);
+ var chunkOrigin = SharedMapSystem.GetChunkIndices(tile, ChunkSize);
if (!allChunks.TryGetValue(chunkOrigin, out var chunk))
{
@@ -171,8 +167,8 @@ internal sealed partial class PowerMonitoringConsoleSystem : SharedPowerMonitori
allChunks[chunkOrigin] = chunk;
}
- var relative = SharedMapSystem.GetChunkRelative(tile, SharedNavMapSystem.ChunkSize);
- var flag = SharedNavMapSystem.GetFlag(relative);
+ var relative = SharedMapSystem.GetChunkRelative(tile, ChunkSize);
+ var flag = GetFlag(relative);
if (args.Anchored)
chunk.PowerCableData[(int) component.CableType] |= flag;
@@ -884,7 +880,7 @@ internal sealed partial class PowerMonitoringConsoleSystem : SharedPowerMonitori
continue;
var tile = _sharedMapSystem.GetTileRef(gridUid, grid, entXform.Coordinates);
- var chunkOrigin = SharedMapSystem.GetChunkIndices(tile.GridIndices, SharedNavMapSystem.ChunkSize);
+ var chunkOrigin = SharedMapSystem.GetChunkIndices(tile.GridIndices, ChunkSize);
if (!allChunks.TryGetValue(chunkOrigin, out var chunk))
{
@@ -892,8 +888,8 @@ internal sealed partial class PowerMonitoringConsoleSystem : SharedPowerMonitori
allChunks[chunkOrigin] = chunk;
}
- var relative = SharedMapSystem.GetChunkRelative(tile.GridIndices, SharedNavMapSystem.ChunkSize);
- var flag = SharedNavMapSystem.GetFlag(relative);
+ var relative = SharedMapSystem.GetChunkRelative(tile.GridIndices, ChunkSize);
+ var flag = GetFlag(relative);
chunk.PowerCableData[(int) cable.CableType] |= flag;
}
@@ -910,7 +906,7 @@ internal sealed partial class PowerMonitoringConsoleSystem : SharedPowerMonitori
var xform = Transform(ent);
var tile = _sharedMapSystem.GetTileRef(gridUid, grid, xform.Coordinates);
var gridIndices = tile.GridIndices;
- var chunkOrigin = SharedMapSystem.GetChunkIndices(gridIndices, SharedNavMapSystem.ChunkSize);
+ var chunkOrigin = SharedMapSystem.GetChunkIndices(gridIndices, ChunkSize);
if (!component.FocusChunks.TryGetValue(chunkOrigin, out var chunk))
{
@@ -918,8 +914,8 @@ internal sealed partial class PowerMonitoringConsoleSystem : SharedPowerMonitori
component.FocusChunks[chunkOrigin] = chunk;
}
- var relative = SharedMapSystem.GetChunkRelative(gridIndices, SharedNavMapSystem.ChunkSize);
- var flag = SharedNavMapSystem.GetFlag(relative);
+ var relative = SharedMapSystem.GetChunkRelative(gridIndices, ChunkSize);
+ var flag = GetFlag(relative);
if (TryComp(ent, out var cable))
chunk.PowerCableData[(int) cable.CableType] |= flag;
diff --git a/Content.Server/Power/Generation/Teg/TegSystem.cs b/Content.Server/Power/Generation/Teg/TegSystem.cs
index 3510a3da45..540bd6c483 100644
--- a/Content.Server/Power/Generation/Teg/TegSystem.cs
+++ b/Content.Server/Power/Generation/Teg/TegSystem.cs
@@ -7,6 +7,7 @@ using Content.Server.DeviceNetwork.Systems;
using Content.Server.NodeContainer;
using Content.Server.NodeContainer.Nodes;
using Content.Server.Power.Components;
+using Content.Shared.Atmos;
using Content.Shared.DeviceNetwork;
using Content.Shared.Examine;
using Content.Shared.Power.Generation.Teg;
diff --git a/Content.Server/Power/Generator/GeneratorExhaustGasSystem.cs b/Content.Server/Power/Generator/GeneratorExhaustGasSystem.cs
index cd85e67221..359c31d75b 100644
--- a/Content.Server/Power/Generator/GeneratorExhaustGasSystem.cs
+++ b/Content.Server/Power/Generator/GeneratorExhaustGasSystem.cs
@@ -1,5 +1,6 @@
using Content.Server.Atmos;
using Content.Server.Atmos.EntitySystems;
+using Content.Shared.Atmos;
using Content.Shared.Power.Generator;
namespace Content.Server.Power.Generator;
diff --git a/Content.Server/Storage/Components/EntityStorageComponent.cs b/Content.Server/Storage/Components/EntityStorageComponent.cs
index 40fdb1b326..3fba89b64a 100644
--- a/Content.Server/Storage/Components/EntityStorageComponent.cs
+++ b/Content.Server/Storage/Components/EntityStorageComponent.cs
@@ -1,4 +1,5 @@
using Content.Server.Atmos;
+using Content.Shared.Atmos;
using Content.Shared.Storage.Components;
using Robust.Shared.GameStates;
diff --git a/Content.Server/Storage/EntitySystems/SpawnItemsOnUseSystem.cs b/Content.Server/Storage/EntitySystems/SpawnItemsOnUseSystem.cs
index c49bfdec93..4c533ede3a 100644
--- a/Content.Server/Storage/EntitySystems/SpawnItemsOnUseSystem.cs
+++ b/Content.Server/Storage/EntitySystems/SpawnItemsOnUseSystem.cs
@@ -82,7 +82,9 @@ namespace Content.Server.Storage.EntitySystems
if (component.Sound != null)
{
- _audio.PlayPvs(component.Sound, uid);
+ // The entity is often deleted, so play the sound at its position rather than parenting
+ var coordinates = Transform(uid).Coordinates;
+ _audio.PlayPvs(component.Sound, coordinates);
}
component.Uses--;
diff --git a/Content.Server/Store/Systems/StoreSystem.cs b/Content.Server/Store/Systems/StoreSystem.cs
index 7998c42f53..e310194778 100644
--- a/Content.Server/Store/Systems/StoreSystem.cs
+++ b/Content.Server/Store/Systems/StoreSystem.cs
@@ -100,7 +100,7 @@ public sealed partial class StoreSystem : EntitySystem
if (args.Handled)
{
var msg = Loc.GetString("store-currency-inserted", ("used", args.Used), ("target", args.Target));
- _popup.PopupEntity(msg, args.Target.Value);
+ _popup.PopupEntity(msg, args.Target.Value, args.User);
QueueDel(args.Used);
}
}
diff --git a/Content.Server/Weapons/Ranged/Systems/GunSystem.cs b/Content.Server/Weapons/Ranged/Systems/GunSystem.cs
index 7449b0c59e..f495f29e4a 100644
--- a/Content.Server/Weapons/Ranged/Systems/GunSystem.cs
+++ b/Content.Server/Weapons/Ranged/Systems/GunSystem.cs
@@ -154,7 +154,7 @@ public sealed partial class GunSystem : SharedGunSystem
});
SetCartridgeSpent(ent.Value, cartridge, true);
- MuzzleFlash(gunUid, cartridge, user);
+ MuzzleFlash(gunUid, cartridge, mapDirection.ToAngle(), user);
Audio.PlayPredicted(gun.SoundGunshotModified, gunUid, user);
if (cartridge.DeleteOnSpawn)
@@ -175,7 +175,7 @@ public sealed partial class GunSystem : SharedGunSystem
// Ammo shoots itself
case AmmoComponent newAmmo:
shotProjectiles.Add(ent!.Value);
- MuzzleFlash(gunUid, newAmmo, user);
+ MuzzleFlash(gunUid, newAmmo, mapDirection.ToAngle(), user);
Audio.PlayPredicted(gun.SoundGunshotModified, gunUid, user);
ShootOrThrow(ent.Value, mapDirection, gunVelocity, gun, gunUid, user);
break;
@@ -326,9 +326,9 @@ public sealed partial class GunSystem : SharedGunSystem
protected override void Popup(string message, EntityUid? uid, EntityUid? user) { }
- protected override void CreateEffect(EntityUid uid, MuzzleFlashEvent message, EntityUid? user = null)
+ protected override void CreateEffect(EntityUid gunUid, MuzzleFlashEvent message, EntityUid? user = null)
{
- var filter = Filter.Pvs(uid, entityManager: EntityManager);
+ var filter = Filter.Pvs(gunUid, entityManager: EntityManager);
if (TryComp(user, out var actor))
filter.RemovePlayer(actor.PlayerSession);
diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/GasArtifactSystem.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/GasArtifactSystem.cs
index e24d31a113..dc054d2318 100644
--- a/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/GasArtifactSystem.cs
+++ b/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/GasArtifactSystem.cs
@@ -2,6 +2,7 @@
using Content.Server.Atmos.EntitySystems;
using Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Components;
using Content.Server.Xenoarchaeology.XenoArtifacts.Events;
+using Content.Shared.Atmos;
namespace Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Systems;
diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/TemperatureArtifactSystem.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/TemperatureArtifactSystem.cs
index f314d4a4fb..e62ce36b5b 100644
--- a/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/TemperatureArtifactSystem.cs
+++ b/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/TemperatureArtifactSystem.cs
@@ -2,6 +2,7 @@
using Content.Server.Atmos.EntitySystems;
using Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Components;
using Content.Server.Xenoarchaeology.XenoArtifacts.Events;
+using Content.Shared.Atmos;
using Robust.Server.GameObjects;
namespace Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Systems;
diff --git a/Content.Shared/Atmos/AtmosDirection.cs b/Content.Shared/Atmos/AtmosDirection.cs
index 09ba521aa9..a8155ef88d 100644
--- a/Content.Shared/Atmos/AtmosDirection.cs
+++ b/Content.Shared/Atmos/AtmosDirection.cs
@@ -104,15 +104,14 @@ namespace Content.Shared.Atmos
{
return direction switch
{
- AtmosDirection.East => Angle.FromDegrees(90),
- AtmosDirection.North => Angle.FromDegrees(180),
- AtmosDirection.West => Angle.FromDegrees(270),
- AtmosDirection.South => Angle.FromDegrees(0),
-
- AtmosDirection.NorthEast => Angle.FromDegrees(135),
- AtmosDirection.NorthWest => Angle.FromDegrees(205),
- AtmosDirection.SouthWest => Angle.FromDegrees(315),
- AtmosDirection.SouthEast => Angle.FromDegrees(45),
+ AtmosDirection.South => Angle.Zero,
+ AtmosDirection.East => new Angle(MathHelper.PiOver2),
+ AtmosDirection.North => new Angle(Math.PI),
+ AtmosDirection.West => new Angle(-MathHelper.PiOver2),
+ AtmosDirection.NorthEast => new Angle(Math.PI*3/4),
+ AtmosDirection.NorthWest => new Angle(-Math.PI*3/4),
+ AtmosDirection.SouthWest => new Angle(-MathHelper.PiOver4),
+ AtmosDirection.SouthEast => new Angle(MathHelper.PiOver4),
_ => throw new ArgumentOutOfRangeException(nameof(direction), $"It was {direction}."),
};
diff --git a/Content.Server/Atmos/GasMixture.cs b/Content.Shared/Atmos/GasMixture.cs
similarity index 98%
rename from Content.Server/Atmos/GasMixture.cs
rename to Content.Shared/Atmos/GasMixture.cs
index 3d73a4d0b1..a676ed6720 100644
--- a/Content.Server/Atmos/GasMixture.cs
+++ b/Content.Shared/Atmos/GasMixture.cs
@@ -1,13 +1,12 @@
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Runtime.CompilerServices;
-using Content.Server.Atmos.Reactions;
-using Content.Shared.Atmos;
using Content.Shared.Atmos.EntitySystems;
+using Content.Shared.Atmos.Reactions;
using Robust.Shared.Serialization;
using Robust.Shared.Utility;
-namespace Content.Server.Atmos
+namespace Content.Shared.Atmos
{
///
/// A general-purpose, variable volume gas mixture.
diff --git a/Content.Shared/Atmos/GasMixtureStringRepresentation.cs b/Content.Shared/Atmos/GasMixtureStringRepresentation.cs
new file mode 100644
index 0000000000..942b2bdc67
--- /dev/null
+++ b/Content.Shared/Atmos/GasMixtureStringRepresentation.cs
@@ -0,0 +1,16 @@
+namespace Content.Shared.Atmos;
+
+public readonly record struct GasMixtureStringRepresentation(float TotalMoles, float Temperature, float Pressure, Dictionary MolesPerGas) : IFormattable
+{
+ public override string ToString()
+ {
+ return $"{Temperature}K {Pressure} kPa";
+ }
+
+ public string ToString(string? format, IFormatProvider? formatProvider)
+ {
+ return ToString();
+ }
+
+ public static implicit operator string(GasMixtureStringRepresentation rep) => rep.ToString();
+}
diff --git a/Content.Shared/Atmos/Reactions/GasReactionEnums.cs b/Content.Shared/Atmos/Reactions/GasReactionEnums.cs
new file mode 100644
index 0000000000..73b8998d40
--- /dev/null
+++ b/Content.Shared/Atmos/Reactions/GasReactionEnums.cs
@@ -0,0 +1,14 @@
+namespace Content.Shared.Atmos.Reactions;
+
+[Flags]
+public enum ReactionResult : byte
+{
+ NoReaction = 0,
+ Reacting = 1,
+ StopReactions = 2,
+}
+
+public enum GasReaction : byte
+{
+ Fire = 0,
+}
diff --git a/Content.Shared/CCVar/CCVars.cs b/Content.Shared/CCVar/CCVars.cs
index 5603e24370..b632eaf9e4 100644
--- a/Content.Shared/CCVar/CCVars.cs
+++ b/Content.Shared/CCVar/CCVars.cs
@@ -1,3 +1,4 @@
+using Content.Shared.Maps;
using Robust.Shared;
using Robust.Shared.Configuration;
@@ -908,6 +909,13 @@ namespace Content.Shared.CCVar
public static readonly CVarDef ExplosionSingleTickAreaLimit =
CVarDef.Create("explosion.single_tick_area_limit", 400, CVar.SERVERONLY);
+ ///
+ /// Whether or not explosions are allowed to create tiles that have
+ /// set to true.
+ ///
+ public static readonly CVarDef ExplosionCanCreateVacuum =
+ CVarDef.Create("explosion.can_create_vacuum", true, CVar.SERVERONLY);
+
/*
* Radiation
*/
@@ -2003,7 +2011,7 @@ namespace Content.Shared.CCVar
// Clippy!
public static readonly CVarDef TippyEntity =
CVarDef.Create("tippy.entity", "Tippy", CVar.SERVER | CVar.REPLICATED);
-
+
/*
* DEBUG
*/
diff --git a/Content.Shared/Follower/FollowerSystem.cs b/Content.Shared/Follower/FollowerSystem.cs
index fc7cccf9bd..6c02b13076 100644
--- a/Content.Shared/Follower/FollowerSystem.cs
+++ b/Content.Shared/Follower/FollowerSystem.cs
@@ -247,6 +247,27 @@ public sealed class FollowerSystem : EntitySystem
StopFollowingEntity(player, uid, followed);
}
}
+
+ ///
+ /// Get the most followed entity.
+ ///
+ public EntityUid? GetMostFollowed()
+ {
+ EntityUid? picked = null;
+ int most = 0;
+ var query = EntityQueryEnumerator();
+ while (query.MoveNext(out var uid, out var comp))
+ {
+ var count = comp.Following.Count;
+ if (count > most)
+ {
+ picked = uid;
+ most = count;
+ }
+ }
+
+ return picked;
+ }
}
public abstract class FollowEvent : EntityEventArgs
diff --git a/Content.Shared/Ghost/SharedGhostSystem.cs b/Content.Shared/Ghost/SharedGhostSystem.cs
index c1c2c3c71e..ad8b86f7dd 100644
--- a/Content.Shared/Ghost/SharedGhostSystem.cs
+++ b/Content.Shared/Ghost/SharedGhostSystem.cs
@@ -125,6 +125,12 @@ namespace Content.Shared.Ghost
}
}
+ ///
+ /// A client to server request for their ghost to be warped to the most followed entity.
+ ///
+ [Serializable, NetSerializable]
+ public sealed class GhostnadoRequestEvent : EntityEventArgs;
+
///
/// A client to server request for their ghost to return to body
///
diff --git a/Content.Shared/Light/Components/SharedExpendableLightComponent.cs b/Content.Shared/Light/Components/SharedExpendableLightComponent.cs
index e40174ab78..001794880a 100644
--- a/Content.Shared/Light/Components/SharedExpendableLightComponent.cs
+++ b/Content.Shared/Light/Components/SharedExpendableLightComponent.cs
@@ -7,7 +7,6 @@ namespace Content.Shared.Light.Components;
[NetworkedComponent]
public abstract partial class SharedExpendableLightComponent : Component
{
- public static readonly AudioParams LoopedSoundParams = new(0, 1, 62.5f, 1, 1, true, 0.3f);
[ViewVariables(VVAccess.ReadOnly)]
public ExpendableLightState CurrentState { get; set; }
diff --git a/Content.Shared/Pinpointer/NavMapComponent.cs b/Content.Shared/Pinpointer/NavMapComponent.cs
index 61315b3db1..d77169d32e 100644
--- a/Content.Shared/Pinpointer/NavMapComponent.cs
+++ b/Content.Shared/Pinpointer/NavMapComponent.cs
@@ -1,3 +1,4 @@
+using System.Linq;
using Content.Shared.Atmos;
using Robust.Shared.GameStates;
using Robust.Shared.Serialization;
@@ -19,53 +20,43 @@ public sealed partial class NavMapComponent : Component
/// Bitmasks that represent chunked tiles.
///
[ViewVariables]
- public Dictionary<(NavMapChunkType, Vector2i), NavMapChunk> Chunks = new();
+ public Dictionary Chunks = new();
///
/// List of station beacons.
///
[ViewVariables]
- public HashSet Beacons = new();
+ public Dictionary Beacons = new();
}
[Serializable, NetSerializable]
-public sealed class NavMapChunk
+public sealed class NavMapChunk(Vector2i origin)
{
///
/// The chunk origin
///
- public readonly Vector2i Origin;
+ [ViewVariables]
+ public readonly Vector2i Origin = origin;
///
- /// Bitmask for tiles, 1 for occupied and 0 for empty. There is a bitmask for each cardinal direction,
- /// representing each edge of the tile, in case the entities inside it do not entirely fill it
+ /// Array containing the chunk's data. The
///
- public Dictionary TileData;
+ [ViewVariables]
+ public int[] TileData = new int[SharedNavMapSystem.ArraySize];
///
/// The last game tick that the chunk was updated
///
[NonSerialized]
public GameTick LastUpdate;
-
- public NavMapChunk(Vector2i origin)
- {
- Origin = origin;
-
- TileData = new()
- {
- [AtmosDirection.North] = 0,
- [AtmosDirection.East] = 0,
- [AtmosDirection.South] = 0,
- [AtmosDirection.West] = 0,
- };
- }
}
public enum NavMapChunkType : byte
{
- Invalid,
- Floor,
- Wall,
- Airlock,
+ // Values represent bit shift offsets when retrieving data in the tile array.
+ Invalid = byte.MaxValue,
+ Floor = 0, // I believe floors have directional information for diagonal tiles?
+ Wall = SharedNavMapSystem.Directions,
+ Airlock = 2 * SharedNavMapSystem.Directions,
}
+
diff --git a/Content.Shared/Pinpointer/SharedNavMapSystem.cs b/Content.Shared/Pinpointer/SharedNavMapSystem.cs
index ebc4f33f0f..0edcd5a437 100644
--- a/Content.Shared/Pinpointer/SharedNavMapSystem.cs
+++ b/Content.Shared/Pinpointer/SharedNavMapSystem.cs
@@ -1,6 +1,6 @@
using System.Diagnostics.CodeAnalysis;
using System.Numerics;
-using Content.Shared.Atmos;
+using System.Runtime.CompilerServices;
using Content.Shared.Tag;
using Robust.Shared.GameStates;
using Robust.Shared.Serialization;
@@ -11,19 +11,22 @@ namespace Content.Shared.Pinpointer;
public abstract class SharedNavMapSystem : EntitySystem
{
- [Dependency] private readonly TagSystem _tagSystem = default!;
- [Dependency] private readonly IGameTiming _gameTiming = default!;
+ public const int Categories = 3;
+ public const int Directions = 4; // Not directly tied to number of atmos directions
- public const byte ChunkSize = 4;
+ public const int ChunkSize = 8;
+ public const int ArraySize = ChunkSize* ChunkSize;
- public readonly NavMapChunkType[] EntityChunkTypes =
- {
- NavMapChunkType.Invalid,
- NavMapChunkType.Wall,
- NavMapChunkType.Airlock,
- };
+ public const int AllDirMask = (1 << Directions) - 1;
+ public const int AirlockMask = AllDirMask << (int) NavMapChunkType.Airlock;
+ public const int WallMask = AllDirMask << (int) NavMapChunkType.Wall;
+ public const int FloorMask = AllDirMask << (int) NavMapChunkType.Floor;
+
+ [Robust.Shared.IoC.Dependency] private readonly TagSystem _tagSystem = default!;
+ [Robust.Shared.IoC.Dependency] private readonly IGameTiming _gameTiming = default!;
private readonly string[] _wallTags = ["Wall", "Window"];
+ private EntityQuery _doorQuery;
public override void Initialize()
{
@@ -31,107 +34,49 @@ public abstract class SharedNavMapSystem : EntitySystem
// Data handling events
SubscribeLocalEvent(OnGetState);
+ _doorQuery = GetEntityQuery();
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int GetTileIndex(Vector2i relativeTile)
+ {
+ return relativeTile.X * ChunkSize + relativeTile.Y;
}
///
- /// Converts the chunk's tile into a bitflag for the slot.
+ /// Inverse of
///
- public static int GetFlag(Vector2i relativeTile)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Vector2i GetTileFromIndex(int index)
{
- return 1 << (relativeTile.X * ChunkSize + relativeTile.Y);
- }
-
- ///
- /// Converts the chunk's tile into a bitflag for the slot.
- ///
- public static Vector2i GetTile(int flag)
- {
- var value = Math.Log2(flag);
- var x = (int) value / ChunkSize;
- var y = (int) value % ChunkSize;
- var result = new Vector2i(x, y);
-
- DebugTools.Assert(GetFlag(result) == flag);
-
+ var x = index / ChunkSize;
+ var y = index % ChunkSize;
return new Vector2i(x, y);
}
- public NavMapChunk SetAllEdgesForChunkTile(NavMapChunk chunk, Vector2i tile)
+ public NavMapChunkType GetEntityType(EntityUid uid)
{
- var relative = SharedMapSystem.GetChunkRelative(tile, ChunkSize);
- var flag = (ushort) GetFlag(relative);
+ if (_doorQuery.HasComp(uid))
+ return NavMapChunkType.Airlock;
- foreach (var (direction, _) in chunk.TileData)
- chunk.TileData[direction] |= flag;
+ if (_tagSystem.HasAnyTag(uid, _wallTags))
+ return NavMapChunkType.Wall;
- return chunk;
+ return NavMapChunkType.Invalid;
}
- public NavMapChunk UnsetAllEdgesForChunkTile(NavMapChunk chunk, Vector2i tile)
- {
- var relative = SharedMapSystem.GetChunkRelative(tile, ChunkSize);
- var flag = (ushort) GetFlag(relative);
- var invFlag = (ushort) ~flag;
-
- foreach (var (direction, _) in chunk.TileData)
- chunk.TileData[direction] &= invFlag;
-
- return chunk;
- }
-
- public ushort GetCombinedEdgesForChunk(Dictionary tile)
- {
- ushort combined = 0;
-
- foreach (var kvp in tile)
- combined |= kvp.Value;
-
- return combined;
- }
-
- public bool AllTileEdgesAreOccupied(Dictionary tileData, Vector2i tile)
- {
- var flag = (ushort) GetFlag(tile);
-
- foreach (var kvp in tileData)
- {
- if ((kvp.Value & flag) == 0)
- return false;
- }
-
- return true;
- }
-
- public NavMapChunkType GetAssociatedEntityChunkType(EntityUid uid)
- {
- var category = NavMapChunkType.Invalid;
-
- if (HasComp(uid))
- category = NavMapChunkType.Airlock;
-
- else if (_tagSystem.HasAnyTag(uid, _wallTags))
- category = NavMapChunkType.Wall;
-
- return category;
- }
-
- protected bool TryCreateNavMapBeaconData(EntityUid uid, NavMapBeaconComponent component, TransformComponent xform, [NotNullWhen(true)] out NavMapBeacon? beaconData)
+ protected bool TryCreateNavMapBeaconData(EntityUid uid, NavMapBeaconComponent component, TransformComponent xform, MetaDataComponent meta, [NotNullWhen(true)] out NavMapBeacon? beaconData)
{
beaconData = null;
if (!component.Enabled || xform.GridUid == null || !xform.Anchored)
return false;
- string? name = component.Text;
- var meta = MetaData(uid);
-
+ var name = component.Text;
if (string.IsNullOrEmpty(name))
name = meta.EntityName;
- beaconData = new NavMapBeacon(meta.NetEntity, component.Color, name, xform.LocalPosition)
- {
- LastUpdate = _gameTiming.CurTick
- };
+ beaconData = new NavMapBeacon(meta.NetEntity, component.Color, name, xform.LocalPosition);
return true;
}
@@ -140,64 +85,36 @@ public abstract class SharedNavMapSystem : EntitySystem
private void OnGetState(EntityUid uid, NavMapComponent component, ref ComponentGetState args)
{
- var chunks = new Dictionary<(NavMapChunkType, Vector2i), Dictionary>();
- var beacons = new HashSet();
+ Dictionary chunks;
// Should this be a full component state or a delta-state?
if (args.FromTick <= component.CreationTick)
{
- foreach (var ((category, origin), chunk) in component.Chunks)
+ // Full state
+ chunks = new(component.Chunks.Count);
+ foreach (var (origin, chunk) in component.Chunks)
{
- var chunkDatum = new Dictionary(chunk.TileData.Count);
-
- foreach (var (direction, tileData) in chunk.TileData)
- chunkDatum[direction] = tileData;
-
- chunks.Add((category, origin), chunkDatum);
+ chunks.Add(origin, chunk.TileData);
}
- var beaconQuery = AllEntityQuery();
-
- while (beaconQuery.MoveNext(out var beaconUid, out var beacon, out var xform))
- {
- if (xform.GridUid != uid)
- continue;
-
- if (!TryCreateNavMapBeaconData(beaconUid, beacon, xform, out var beaconData))
- continue;
-
- beacons.Add(beaconData.Value);
- }
-
- args.State = new NavMapComponentState(chunks, beacons);
+ args.State = new NavMapComponentState(chunks, component.Beacons);
return;
}
- foreach (var ((category, origin), chunk) in component.Chunks)
+ chunks = new();
+ foreach (var (origin, chunk) in component.Chunks)
{
if (chunk.LastUpdate < args.FromTick)
continue;
- var chunkDatum = new Dictionary(chunk.TileData.Count);
-
- foreach (var (direction, tileData) in chunk.TileData)
- chunkDatum[direction] = tileData;
-
- chunks.Add((category, origin), chunkDatum);
+ chunks.Add(origin, chunk.TileData);
}
- foreach (var beacon in component.Beacons)
- {
- if (beacon.LastUpdate < args.FromTick)
- continue;
-
- beacons.Add(beacon);
- }
-
- args.State = new NavMapComponentState(chunks, beacons)
+ args.State = new NavMapComponentState(chunks, component.Beacons)
{
+ // TODO NAVMAP cache a single AllChunks hashset in the component.
+ // Or maybe just only send them if a chunk gets removed.
AllChunks = new(component.Chunks.Keys),
- AllBeacons = new(component.Beacons)
};
}
@@ -206,22 +123,18 @@ public abstract class SharedNavMapSystem : EntitySystem
#region: System messages
[Serializable, NetSerializable]
- protected sealed class NavMapComponentState : ComponentState, IComponentDeltaState
+ protected sealed class NavMapComponentState(
+ Dictionary chunks,
+ Dictionary beacons)
+ : ComponentState, IComponentDeltaState
{
- public Dictionary<(NavMapChunkType, Vector2i), Dictionary> Chunks = new();
- public HashSet Beacons = new();
+ public Dictionary Chunks = chunks;
+ public Dictionary Beacons = beacons;
// Required to infer deleted/missing chunks for delta states
- public HashSet<(NavMapChunkType, Vector2i)>? AllChunks;
- public HashSet? AllBeacons;
+ public HashSet? AllChunks;
- public NavMapComponentState(Dictionary<(NavMapChunkType, Vector2i), Dictionary> chunks, HashSet beacons)
- {
- Chunks = chunks;
- Beacons = beacons;
- }
-
- public bool FullState => (AllChunks == null || AllBeacons == null);
+ public bool FullState => AllChunks == null;
public void ApplyToFullState(IComponentState fullState)
{
@@ -229,25 +142,25 @@ public abstract class SharedNavMapSystem : EntitySystem
var state = (NavMapComponentState) fullState;
DebugTools.Assert(state.FullState);
- // Update chunks
foreach (var key in state.Chunks.Keys)
{
if (!AllChunks!.Contains(key))
state.Chunks.Remove(key);
}
- foreach (var (chunk, data) in Chunks)
- state.Chunks[chunk] = new(data);
-
- // Update beacons
- foreach (var beacon in state.Beacons)
+ foreach (var (index, data) in Chunks)
{
- if (!AllBeacons!.Contains(beacon))
- state.Beacons.Remove(beacon);
+ if (!state.Chunks.TryGetValue(index, out var stateValue))
+ state.Chunks[index] = stateValue = new int[data.Length];
+
+ Array.Copy(data, stateValue, data.Length);
}
- foreach (var beacon in Beacons)
- state.Beacons.Add(beacon);
+ state.Beacons.Clear();
+ foreach (var (nuid, beacon) in Beacons)
+ {
+ state.Beacons.Add(nuid, beacon);
+ }
}
public IComponentState CreateNewFullState(IComponentState fullState)
@@ -256,36 +169,26 @@ public abstract class SharedNavMapSystem : EntitySystem
var state = (NavMapComponentState) fullState;
DebugTools.Assert(state.FullState);
- var chunks = new Dictionary<(NavMapChunkType, Vector2i), Dictionary>();
- var beacons = new HashSet();
-
- foreach (var (chunk, data) in Chunks)
- chunks[chunk] = new(data);
-
- foreach (var (chunk, data) in state.Chunks)
+ var chunks = new Dictionary(state.Chunks.Count);
+ foreach (var (index, data) in state.Chunks)
{
- if (AllChunks!.Contains(chunk))
- chunks.TryAdd(chunk, new(data));
+ if (!AllChunks!.Contains(index))
+ continue;
+
+ var newData = chunks[index] = new int[ArraySize];
+
+ if (Chunks.TryGetValue(index, out var updatedData))
+ Array.Copy(newData, updatedData, ArraySize);
+ else
+ Array.Copy(newData, data, ArraySize);
}
- foreach (var beacon in Beacons)
- beacons.Add(new NavMapBeacon(beacon.NetEnt, beacon.Color, beacon.Text, beacon.Position));
-
- foreach (var beacon in state.Beacons)
- {
- if (AllBeacons!.Contains(beacon))
- beacons.Add(new NavMapBeacon(beacon.NetEnt, beacon.Color, beacon.Text, beacon.Position));
- }
-
- return new NavMapComponentState(chunks, beacons);
+ return new NavMapComponentState(chunks, new(Beacons));
}
}
[Serializable, NetSerializable]
- public record struct NavMapBeacon(NetEntity NetEnt, Color Color, string Text, Vector2 Position)
- {
- public GameTick LastUpdate;
- }
+ public record struct NavMapBeacon(NetEntity NetEnt, Color Color, string Text, Vector2 Position);
#endregion
}
diff --git a/Content.Shared/Players/PlayTimeTracking/PlayTimeTrackingShared.cs b/Content.Shared/Players/PlayTimeTracking/PlayTimeTrackingShared.cs
index e300524d87..ccaf9c17dd 100644
--- a/Content.Shared/Players/PlayTimeTracking/PlayTimeTrackingShared.cs
+++ b/Content.Shared/Players/PlayTimeTracking/PlayTimeTrackingShared.cs
@@ -1,9 +1,18 @@
-namespace Content.Shared.Players.PlayTimeTracking;
+using Content.Shared.Dataset;
+
+namespace Content.Shared.Players.PlayTimeTracking;
public static class PlayTimeTrackingShared
{
///
/// The prototype ID of the play time tracker that represents overall playtime, i.e. not tied to any one role.
///
+ [ValidatePrototypeId]
public const string TrackerOverall = "Overall";
+
+ ///
+ /// The prototype ID of the play time tracker that represents admin time, when a player is in game as admin.
+ ///
+ [ValidatePrototypeId]
+ public const string TrackerAdmin = "Admin";
}
diff --git a/Content.Shared/Power/SharedPowerMonitoringConsoleSystem.cs b/Content.Shared/Power/SharedPowerMonitoringConsoleSystem.cs
index dc4af23c23..749f0233aa 100644
--- a/Content.Shared/Power/SharedPowerMonitoringConsoleSystem.cs
+++ b/Content.Shared/Power/SharedPowerMonitoringConsoleSystem.cs
@@ -1,3 +1,4 @@
+using System.Runtime.CompilerServices;
using JetBrains.Annotations;
namespace Content.Shared.Power;
@@ -5,4 +6,23 @@ namespace Content.Shared.Power;
[UsedImplicitly]
public abstract class SharedPowerMonitoringConsoleSystem : EntitySystem
{
+ // Chunk size is limited as we require ChunkSize^2 <= 32 (number of bits in an int)
+ public const int ChunkSize = 5;
+
+ ///
+ /// Converts the chunk's tile into a bitflag for the slot.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int GetFlag(Vector2i relativeTile)
+ {
+ return 1 << (relativeTile.X * ChunkSize + relativeTile.Y);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Vector2i GetTileFromIndex(int index)
+ {
+ var x = index / ChunkSize;
+ var y = index % ChunkSize;
+ return new Vector2i(x, y);
+ }
}
diff --git a/Content.Shared/Preferences/HumanoidCharacterProfile.cs b/Content.Shared/Preferences/HumanoidCharacterProfile.cs
index 1e57e0d83a..84078ba6e9 100644
--- a/Content.Shared/Preferences/HumanoidCharacterProfile.cs
+++ b/Content.Shared/Preferences/HumanoidCharacterProfile.cs
@@ -356,6 +356,7 @@ namespace Content.Shared.Preferences
if (Age != other.Age) return false;
if (Sex != other.Sex) return false;
if (Gender != other.Gender) return false;
+ if (Species != other.Species) return false;
if (PreferenceUnavailable != other.PreferenceUnavailable) return false;
if (SpawnPriority != other.SpawnPriority) return false;
if (!_jobPriorities.SequenceEqual(other._jobPriorities)) return false;
diff --git a/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs b/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs
index 17dca959ff..223e13ff13 100644
--- a/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs
+++ b/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs
@@ -137,11 +137,8 @@ public abstract class SharedStorageSystem : EntitySystem
private void OnMapInit(Entity entity, ref MapInitEvent args)
{
- if (TryComp(entity, out var useDelayComp))
- {
- UseDelay.SetLength((entity, useDelayComp), entity.Comp.QuickInsertCooldown, QuickInsertUseDelayID);
- UseDelay.SetLength((entity, useDelayComp), entity.Comp.OpenUiCooldown, OpenUiUseDelayID);
- }
+ UseDelay.SetLength(entity.Owner, entity.Comp.QuickInsertCooldown, QuickInsertUseDelayID);
+ UseDelay.SetLength(entity.Owner, entity.Comp.OpenUiCooldown, OpenUiUseDelayID);
}
private void OnStorageGetState(EntityUid uid, StorageComponent component, ref ComponentGetState args)
diff --git a/Content.Shared/Tag/TagSystem.cs b/Content.Shared/Tag/TagSystem.cs
index 62197dc319..fdb7de1f75 100644
--- a/Content.Shared/Tag/TagSystem.cs
+++ b/Content.Shared/Tag/TagSystem.cs
@@ -9,9 +9,12 @@ public sealed class TagSystem : EntitySystem
{
[Dependency] private readonly IPrototypeManager _proto = default!;
+ private EntityQuery _tagQuery;
+
public override void Initialize()
{
base.Initialize();
+ _tagQuery = GetEntityQuery();
SubscribeLocalEvent(OnTagGetState);
SubscribeLocalEvent(OnTagHandleState);
@@ -124,7 +127,7 @@ public sealed class TagSystem : EntitySystem
///
public bool TryAddTag(EntityUid entity, string id)
{
- return TryComp(entity, out var component) &&
+ return _tagQuery.TryComp(entity, out var component) &&
AddTag(entity, component, id);
}
@@ -142,7 +145,7 @@ public sealed class TagSystem : EntitySystem
///
public bool TryAddTags(EntityUid entity, params string[] ids)
{
- return TryComp(entity, out var component) &&
+ return _tagQuery.TryComp(entity, out var component) &&
AddTags(entity, component, ids);
}
@@ -160,7 +163,7 @@ public sealed class TagSystem : EntitySystem
///
public bool TryAddTags(EntityUid entity, IEnumerable ids)
{
- return TryComp(entity, out var component) &&
+ return _tagQuery.TryComp(entity, out var component) &&
AddTags(entity, component, ids);
}
@@ -175,7 +178,7 @@ public sealed class TagSystem : EntitySystem
///
public bool HasTag(EntityUid entity, string id)
{
- return TryComp(entity, out var component) &&
+ return _tagQuery.TryComp(entity, out var component) &&
HasTag(component, id);
}
@@ -210,7 +213,7 @@ public sealed class TagSystem : EntitySystem
///
public bool HasAllTags(EntityUid entity, List ids)
{
- return TryComp(entity, out var component) &&
+ return _tagQuery.TryComp(entity, out var component) &&
HasAllTags(component, ids);
}
@@ -225,7 +228,7 @@ public sealed class TagSystem : EntitySystem
///
public bool HasAllTags(EntityUid entity, IEnumerable ids)
{
- return TryComp(entity, out var component) &&
+ return _tagQuery.TryComp(entity, out var component) &&
HasAllTags(component, ids);
}
@@ -234,18 +237,33 @@ public sealed class TagSystem : EntitySystem
///
/// The entity to check.
/// The tags to check for.
+ /// true if they all exist, false otherwise.
+ ///
+ /// Thrown if one of the ids represents an unregistered .
+ ///
+ public bool HasAllTags(EntityUid entity, List> ids)
+ {
+ return TryComp(entity, out var component) &&
+ HasAllTags(component, ids);
+ }
+
+ ///
+ /// Checks if any of the given tags have been added to an entity.
+ ///
+ /// The entity to check.
+ /// The tags to check for.
/// true if any of them exist, false otherwise.
///
/// Thrown if one of the ids represents an unregistered .
///
public bool HasAnyTag(EntityUid entity, params string[] ids)
{
- return TryComp(entity, out var component) &&
+ return _tagQuery.TryComp(entity, out var component) &&
HasAnyTag(component, ids);
}
///
- /// Checks if all of the given tags have been added to an entity.
+ /// Checks if any of the given tags have been added to an entity.
///
/// The entity to check.
/// The tag to check for.
@@ -256,7 +274,7 @@ public sealed class TagSystem : EntitySystem
public bool HasAnyTag(EntityUid entity, string id) => HasTag(entity, id);
///
- /// Checks if all of the given tags have been added to an entity.
+ /// Checks if any of the given tags have been added to an entity.
///
/// The entity to check.
/// The tags to check for.
@@ -265,13 +283,28 @@ public sealed class TagSystem : EntitySystem
/// Thrown if one of the ids represents an unregistered .
///
public bool HasAnyTag(EntityUid entity, List ids)
+ {
+ return _tagQuery.TryComp(entity, out var component) &&
+ HasAnyTag(component, ids);
+ }
+
+ ///
+ /// Checks if any of the given tags have been added to an entity.
+ ///
+ /// The entity to check.
+ /// The tags to check for.
+ /// true if any of them exist, false otherwise.
+ ///
+ /// Thrown if one of the ids represents an unregistered .
+ ///
+ public bool HasAnyTag(EntityUid entity, List> ids)
{
return TryComp(entity, out var component) &&
HasAnyTag(component, ids);
}
///
- /// Checks if all of the given tags have been added to an entity.
+ /// Checks if any of the given tags have been added to an entity.
///
/// The entity to check.
/// The tags to check for.
@@ -281,7 +314,7 @@ public sealed class TagSystem : EntitySystem
///
public bool HasAnyTag(EntityUid entity, IEnumerable ids)
{
- return TryComp(entity, out var component) &&
+ return _tagQuery.TryComp(entity, out var component) &&
HasAnyTag(component, ids);
}
@@ -298,7 +331,7 @@ public sealed class TagSystem : EntitySystem
///
public bool RemoveTag(EntityUid entity, string id)
{
- return TryComp(entity, out var component) &&
+ return _tagQuery.TryComp(entity, out var component) &&
RemoveTag(entity, component, id);
}
@@ -315,7 +348,7 @@ public sealed class TagSystem : EntitySystem
///
public bool RemoveTags(EntityUid entity, params string[] ids)
{
- return TryComp(entity, out var component) &&
+ return _tagQuery.TryComp(entity, out var component) &&
RemoveTags(entity, component, ids);
}
@@ -332,7 +365,7 @@ public sealed class TagSystem : EntitySystem
///
public bool RemoveTags(EntityUid entity, IEnumerable ids)
{
- return TryComp(entity, out var component) &&
+ return _tagQuery.TryComp(entity, out var component) &&
RemoveTags(entity, component, ids);
}
@@ -478,6 +511,26 @@ public sealed class TagSystem : EntitySystem
return true;
}
+ ///
+ /// Checks if all of the given tags have been added.
+ ///
+ /// The tags to check for.
+ /// true if they all exist, false otherwise.
+ ///
+ /// Thrown if one of the ids represents an unregistered .
+ ///
+ public bool HasAllTags(TagComponent component, List> ids)
+ {
+ var stringIds = new List();
+ foreach (var tag in ids)
+ {
+ stringIds.Add(tag.Id);
+ }
+
+ return HasAllTags(component, stringIds);
+ }
+
+
///
/// Checks if any of the given tags have been added.
///
@@ -488,7 +541,15 @@ public sealed class TagSystem : EntitySystem
///
public bool HasAnyTag(TagComponent component, params string[] ids)
{
- return HasAnyTag(component, ids.AsEnumerable());
+ foreach (var id in ids)
+ {
+ AssertValidTag(id);
+
+ if (component.Tags.Contains(id))
+ return true;
+ }
+
+ return false;
}
@@ -548,6 +609,25 @@ public sealed class TagSystem : EntitySystem
return false;
}
+ ///
+ /// Checks if any of the given tags have been added.
+ ///
+ /// The tags to check for.
+ /// true if any of them exist, false otherwise.
+ ///
+ /// Thrown if one of the ids represents an unregistered .
+ ///
+ public bool HasAnyTag(TagComponent comp, List> ids)
+ {
+ var stringIds = new List();
+ foreach (var tag in ids)
+ {
+ stringIds.Add(tag.Id);
+ }
+
+ return HasAnyTag(comp, stringIds);
+ }
+
///
/// Tries to remove a tag if it exists.
///
diff --git a/Content.Shared/Timing/UseDelaySystem.cs b/Content.Shared/Timing/UseDelaySystem.cs
index bc2a709175..9816d0185a 100644
--- a/Content.Shared/Timing/UseDelaySystem.cs
+++ b/Content.Shared/Timing/UseDelaySystem.cs
@@ -47,7 +47,7 @@ public sealed class UseDelaySystem : EntitySystem
{
// Set default delay length from the prototype
// This makes it easier for simple use cases that only need a single delay
- SetLength(ent, ent.Comp.Delay, DefaultId);
+ SetLength((ent, ent.Comp), ent.Comp.Delay, DefaultId);
}
private void OnUnpaused(Entity ent, ref EntityUnpausedEvent args)
@@ -62,9 +62,14 @@ public sealed class UseDelaySystem : EntitySystem
///
/// Sets the length of the delay with the specified ID.
///
- public bool SetLength(Entity ent, TimeSpan length, string id = DefaultId)
+ ///
+ /// This will add a UseDelay component to the entity if it doesn't have one.
+ ///
+ public bool SetLength(Entity ent, TimeSpan length, string id = DefaultId)
{
- if (ent.Comp.Delays.TryGetValue(id, out var entry))
+ EnsureComp(ent.Owner, out var comp);
+
+ if (comp.Delays.TryGetValue(id, out var entry))
{
if (entry.Length == length)
return true;
@@ -73,7 +78,7 @@ public sealed class UseDelaySystem : EntitySystem
}
else
{
- ent.Comp.Delays.Add(id, new UseDelayInfo(length));
+ comp.Delays.Add(id, new UseDelayInfo(length));
}
Dirty(ent);
diff --git a/Content.Shared/Weapons/Ranged/Events/MuzzleFlashEvent.cs b/Content.Shared/Weapons/Ranged/Events/MuzzleFlashEvent.cs
index 91f5e6cd86..10d4c2fe3c 100644
--- a/Content.Shared/Weapons/Ranged/Events/MuzzleFlashEvent.cs
+++ b/Content.Shared/Weapons/Ranged/Events/MuzzleFlashEvent.cs
@@ -11,15 +11,12 @@ public sealed class MuzzleFlashEvent : EntityEventArgs
public NetEntity Uid;
public string Prototype;
- ///
- /// Should the effect match the rotation of the entity.
- ///
- public bool MatchRotation;
+ public Angle Angle;
- public MuzzleFlashEvent(NetEntity uid, string prototype, bool matchRotation = false)
+ public MuzzleFlashEvent(NetEntity uid, string prototype, Angle angle)
{
Uid = uid;
Prototype = prototype;
- MatchRotation = matchRotation;
+ Angle = angle;
}
}
diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs
index 129d536a70..51e2e1358f 100644
--- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs
+++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs
@@ -136,7 +136,6 @@ public abstract partial class SharedGunSystem : EntitySystem
return;
gun.ShootCoordinates = GetCoordinates(msg.Coordinates);
- Log.Debug($"Set shoot coordinates to {gun.ShootCoordinates}");
AttemptShoot(user.Value, ent, gun);
}
@@ -195,7 +194,6 @@ public abstract partial class SharedGunSystem : EntitySystem
if (gun.ShotCounter == 0)
return;
- Log.Debug($"Stopped shooting {ToPrettyString(uid)}");
gun.ShotCounter = 0;
gun.ShootCoordinates = null;
Dirty(uid, gun);
@@ -461,7 +459,7 @@ public abstract partial class SharedGunSystem : EntitySystem
RemCompDeferred(uid);
}
- protected void MuzzleFlash(EntityUid gun, AmmoComponent component, EntityUid? user = null)
+ protected void MuzzleFlash(EntityUid gun, AmmoComponent component, Angle worldAngle, EntityUid? user = null)
{
var attemptEv = new GunMuzzleFlashAttemptEvent();
RaiseLocalEvent(gun, ref attemptEv);
@@ -473,7 +471,7 @@ public abstract partial class SharedGunSystem : EntitySystem
if (sprite == null)
return;
- var ev = new MuzzleFlashEvent(GetNetEntity(gun), sprite, user == gun);
+ var ev = new MuzzleFlashEvent(GetNetEntity(gun), sprite, worldAngle);
CreateEffect(gun, ev, user);
}
@@ -522,7 +520,7 @@ public abstract partial class SharedGunSystem : EntitySystem
Dirty(gun);
}
- protected abstract void CreateEffect(EntityUid uid, MuzzleFlashEvent message, EntityUid? user = null);
+ protected abstract void CreateEffect(EntityUid gunUid, MuzzleFlashEvent message, EntityUid? user = null);
///
/// Used for animated effects on the client.
diff --git a/Content.Shared/Whitelist/EntityWhitelist.cs b/Content.Shared/Whitelist/EntityWhitelist.cs
index b412a09b98..7fa6ce7f82 100644
--- a/Content.Shared/Whitelist/EntityWhitelist.cs
+++ b/Content.Shared/Whitelist/EntityWhitelist.cs
@@ -1,103 +1,121 @@
+using Content.Shared.Item;
using Content.Shared.Tag;
+using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
-namespace Content.Shared.Whitelist
+namespace Content.Shared.Whitelist;
+
+///
+/// Used to determine whether an entity fits a certain whitelist.
+/// Does not whitelist by prototypes, since that is undesirable; you're better off just adding a tag to all
+/// entity prototypes that need to be whitelisted, and checking for that.
+///
+///
+/// whitelist:
+/// tags:
+/// - Cigarette
+/// - FirelockElectronics
+/// components:
+/// - Buckle
+/// - AsteroidRock
+/// sizes:
+/// - Tiny
+/// - Large
+///
+[DataDefinition]
+[Serializable, NetSerializable]
+public sealed partial class EntityWhitelist
{
///
- /// Used to determine whether an entity fits a certain whitelist.
- /// Does not whitelist by prototypes, since that is undesirable; you're better off just adding a tag to all
- /// entity prototypes that need to be whitelisted, and checking for that.
+ /// Component names that are allowed in the whitelist.
///
- ///
- /// whitelist:
- /// tags:
- /// - Cigarette
- /// - FirelockElectronics
- /// components:
- /// - Buckle
- /// - AsteroidRock
- ///
- [DataDefinition]
- [Serializable, NetSerializable]
- public sealed partial class EntityWhitelist
+ [DataField] public string[]? Components;
+ // TODO yaml validation
+
+ ///
+ /// Item sizes that are allowed in the whitelist.
+ ///
+ [DataField]
+ public List>? Sizes;
+
+ [NonSerialized]
+ private List? _registrations;
+
+ ///
+ /// Tags that are allowed in the whitelist.
+ ///
+ [DataField]
+ public List>? Tags;
+
+ ///
+ /// If false, an entity only requires one of these components or tags to pass the whitelist. If true, an
+ /// entity requires to have ALL of these components and tags to pass.
+ /// The "Sizes" criteria will ignores this, since an item can only have one size.
+ ///
+ [DataField]
+ public bool RequireAll;
+
+ public void UpdateRegistrations()
{
- ///
- /// Component names that are allowed in the whitelist.
- ///
- [DataField("components")] public string[]? Components = null;
- // TODO yaml validation
- [NonSerialized]
- private List? _registrations = null;
+ if (Components == null)
+ return;
- ///
- /// Tags that are allowed in the whitelist.
- ///
- [DataField("tags", customTypeSerializer:typeof(PrototypeIdListSerializer))]
- public List? Tags = null;
-
- ///
- /// If false, an entity only requires one of these components or tags to pass the whitelist. If true, an
- /// entity requires to have ALL of these components and tags to pass.
- ///
- [DataField("requireAll")]
- public bool RequireAll = false;
-
- public void UpdateRegistrations()
+ var compFact = IoCManager.Resolve();
+ _registrations = new List();
+ foreach (var name in Components)
{
- if (Components == null) return;
-
- var compfact = IoCManager.Resolve();
- _registrations = new List();
- foreach (var name in Components)
+ var availability = compFact.GetComponentAvailability(name);
+ if (compFact.TryGetRegistration(name, out var registration)
+ && availability == ComponentAvailability.Available)
{
- var availability = compfact.GetComponentAvailability(name);
- if (compfact.TryGetRegistration(name, out var registration)
- && availability == ComponentAvailability.Available)
- {
- _registrations.Add(registration);
- }
- else if (availability == ComponentAvailability.Unknown)
- {
- Logger.Warning($"Unknown component name {name} passed to EntityWhitelist!");
- }
+ _registrations.Add(registration);
}
- }
-
- ///
- /// Returns whether a given entity fits the whitelist.
- ///
- public bool IsValid(EntityUid uid, IEntityManager? entityManager = null)
- {
- if (Components != null && _registrations == null)
- UpdateRegistrations();
-
- IoCManager.Resolve(ref entityManager);
- if (_registrations != null)
+ else if (availability == ComponentAvailability.Unknown)
{
- foreach (var reg in _registrations)
- {
- if (entityManager.HasComponent(uid, reg.Type))
- {
- if (!RequireAll)
- return true;
- }
- else if (RequireAll)
- return false;
- }
+ Logger.Warning($"Unknown component name {name} passed to EntityWhitelist!");
}
-
- if (Tags != null && entityManager.TryGetComponent(uid, out TagComponent? tags))
- {
- var tagSystem = entityManager.System();
- return RequireAll ? tagSystem.HasAllTags(tags, Tags) : tagSystem.HasAnyTag(tags, Tags);
- }
-
- if (RequireAll)
- return true;
-
- return false;
}
}
+
+ ///
+ /// Returns whether a given entity fits the whitelist.
+ ///
+ public bool IsValid(EntityUid uid, IEntityManager? entityManager = null)
+ {
+ if (Components != null && _registrations == null)
+ UpdateRegistrations();
+
+ IoCManager.Resolve(ref entityManager);
+ if (_registrations != null)
+ {
+ foreach (var reg in _registrations)
+ {
+ if (entityManager.HasComponent(uid, reg.Type))
+ {
+ if (!RequireAll)
+ return true;
+ }
+ else if (RequireAll)
+ return false;
+ }
+ }
+
+ if (Sizes != null && entityManager.TryGetComponent(uid, out ItemComponent? itemComp))
+ {
+ if (Sizes.Contains(itemComp.Size))
+ return true;
+ }
+
+ if (Tags != null && entityManager.TryGetComponent(uid, out TagComponent? tags))
+ {
+ var tagSystem = entityManager.System();
+ return RequireAll ? tagSystem.HasAllTags(tags, Tags) : tagSystem.HasAnyTag(tags, Tags);
+ }
+
+ if (RequireAll)
+ return true;
+
+ return false;
+ }
}
diff --git a/Resources/Audio/Animals/attributions.yml b/Resources/Audio/Animals/attributions.yml
index c34832a807..7fd7e8b2e7 100644
--- a/Resources/Audio/Animals/attributions.yml
+++ b/Resources/Audio/Animals/attributions.yml
@@ -7,7 +7,7 @@
license: "CC-BY-3.0"
copyright: "Modified from 'Meow 4.wav' by freesound user 'TRNGLE. The original audio was trimmed, split to mono, and converted from WAV to OGG format"
source: "https://freesound.org/people/TRNGLE/sounds/368006/"
-
+
- files: ["cat_meow2.ogg"]
license: "CC-BY-3.0"
copyright: "Created by freesound user 'TRNGLE. The original audio split to mono, and converted from WAV to OGG format"
@@ -117,24 +117,42 @@
license: "CC-BY-4.0"
copyright: "Audio is recorded/created by Pfranzen 'FreeSound.org'. The original audio was trimmed and renamed"
source: "https://freesound.org/people/pfranzen/sounds/322744/"
-
+
- files: ["dog_bark1.ogg"]
license: "CC0-1.0"
copyright: "Audio is recorded/created by KFerentchak 'FreeSound.org'. The original audio was trimmed and renamed"
- source: "https://freesound.org/people/KFerentchak/sounds/235912/"
-
+ source: "https://freesound.org/people/KFerentchak/sounds/235912/"
+
- files: ["dog_bark2.ogg"]
license: "CC0-1.0"
copyright: "Audio is recorded/created by KFerentchak 'FreeSound.org'. The original audio was trimmed and renamed"
- source: "https://freesound.org/people/KFerentchak/sounds/235912/"
-
+ source: "https://freesound.org/people/KFerentchak/sounds/235912/"
+
- files: ["dog_bark3.ogg"]
license: "CC0-1.0"
copyright: "Audio is recorded/created by KFerentchak 'FreeSound.org'. The original audio was trimmed and renamed"
source: "https://freesound.org/people/KFerentchak/sounds/235912/"
-
+
- files: ["nymph_chirp.ogg"]
license: "CC-BY-SA-3.0"
copyright: "Taken from ParadiseSS13"
source: "https://github.com/ParadiseSS13/Paradise/commit/a34f1054cef5a44a67fdac3b67b811137c6071dd"
-
\ No newline at end of file
+
+- files:
+ - fox1.ogg
+ - fox2.ogg
+ - fox3.ogg
+ - fox4.ogg
+ - fox5.ogg
+ - fox6.ogg
+ - fox7.ogg
+ - fox8.ogg
+ - fox9.ogg
+ - fox10.ogg
+ - fox11.ogg
+ - fox12.ogg
+ - fox13.ogg
+ - fox14.ogg
+ copyright: "Created by fujiwaranao"
+ license: "CC-BY-NC-SA-4.0"
+ source: "https://github.com/space-wizards/space-station-14/pull/27578"
diff --git a/Resources/Audio/Animals/fox1.ogg b/Resources/Audio/Animals/fox1.ogg
new file mode 100644
index 0000000000..40fe16cc52
Binary files /dev/null and b/Resources/Audio/Animals/fox1.ogg differ
diff --git a/Resources/Audio/Animals/fox10.ogg b/Resources/Audio/Animals/fox10.ogg
new file mode 100644
index 0000000000..2a9e156dc5
Binary files /dev/null and b/Resources/Audio/Animals/fox10.ogg differ
diff --git a/Resources/Audio/Animals/fox11.ogg b/Resources/Audio/Animals/fox11.ogg
new file mode 100644
index 0000000000..d294137dc1
Binary files /dev/null and b/Resources/Audio/Animals/fox11.ogg differ
diff --git a/Resources/Audio/Animals/fox12.ogg b/Resources/Audio/Animals/fox12.ogg
new file mode 100644
index 0000000000..c413af81c7
Binary files /dev/null and b/Resources/Audio/Animals/fox12.ogg differ
diff --git a/Resources/Audio/Animals/fox13.ogg b/Resources/Audio/Animals/fox13.ogg
new file mode 100644
index 0000000000..197a9e4339
Binary files /dev/null and b/Resources/Audio/Animals/fox13.ogg differ
diff --git a/Resources/Audio/Animals/fox14.ogg b/Resources/Audio/Animals/fox14.ogg
new file mode 100644
index 0000000000..1d9c99889d
Binary files /dev/null and b/Resources/Audio/Animals/fox14.ogg differ
diff --git a/Resources/Audio/Animals/fox2.ogg b/Resources/Audio/Animals/fox2.ogg
new file mode 100644
index 0000000000..7aeb7da911
Binary files /dev/null and b/Resources/Audio/Animals/fox2.ogg differ
diff --git a/Resources/Audio/Animals/fox3.ogg b/Resources/Audio/Animals/fox3.ogg
new file mode 100644
index 0000000000..561b313f41
Binary files /dev/null and b/Resources/Audio/Animals/fox3.ogg differ
diff --git a/Resources/Audio/Animals/fox4.ogg b/Resources/Audio/Animals/fox4.ogg
new file mode 100644
index 0000000000..6805d0e848
Binary files /dev/null and b/Resources/Audio/Animals/fox4.ogg differ
diff --git a/Resources/Audio/Animals/fox5.ogg b/Resources/Audio/Animals/fox5.ogg
new file mode 100644
index 0000000000..5aefa939cc
Binary files /dev/null and b/Resources/Audio/Animals/fox5.ogg differ
diff --git a/Resources/Audio/Animals/fox6.ogg b/Resources/Audio/Animals/fox6.ogg
new file mode 100644
index 0000000000..d23cca5ff2
Binary files /dev/null and b/Resources/Audio/Animals/fox6.ogg differ
diff --git a/Resources/Audio/Animals/fox7.ogg b/Resources/Audio/Animals/fox7.ogg
new file mode 100644
index 0000000000..d4da91e73b
Binary files /dev/null and b/Resources/Audio/Animals/fox7.ogg differ
diff --git a/Resources/Audio/Animals/fox8.ogg b/Resources/Audio/Animals/fox8.ogg
new file mode 100644
index 0000000000..52337a640b
Binary files /dev/null and b/Resources/Audio/Animals/fox8.ogg differ
diff --git a/Resources/Audio/Animals/fox9.ogg b/Resources/Audio/Animals/fox9.ogg
new file mode 100644
index 0000000000..eb161ccdaf
Binary files /dev/null and b/Resources/Audio/Animals/fox9.ogg differ
diff --git a/Resources/Changelog/Admin.yml b/Resources/Changelog/Admin.yml
index fe1a1f56d7..f5d74cf9b6 100644
--- a/Resources/Changelog/Admin.yml
+++ b/Resources/Changelog/Admin.yml
@@ -194,5 +194,12 @@ Entries:
id: 25
time: '2024-04-27T11:17:47.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/26930
+- author: Titian3
+ changes:
+ - message: Added admin playtime tracking and included it in overall playtime tracking.
+ type: Add
+ id: 26
+ time: '2024-05-02T06:23:23.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/24945
Name: Admin
Order: 1
diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml
index f6e735e73c..718882f086 100644
--- a/Resources/Changelog/Changelog.yml
+++ b/Resources/Changelog/Changelog.yml
@@ -1,153 +1,4 @@
Entries:
-- author: Fildrance
- changes:
- - message: now cryo pod health analyzer updates atomatically!
- type: Fix
- id: 5997
- time: '2024-02-21T14:47:23.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/25109
-- author: landwhale
- changes:
- - message: Drink jugs can no longer be used by chemistry in place of a beaker.
- type: Fix
- - message: Updated names of several drink jugs to differentiate them from chem-specific
- variants.
- type: Tweak
- id: 5998
- time: '2024-02-21T23:26:29.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/25450
-- author: Killerqu00
- changes:
- - message: EVA helmets are now quick-equippable again
- type: Fix
- id: 5999
- time: '2024-02-21T23:41:26.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/25448
-- author: genderGeometries
- changes:
- - message: Crops are now harvested with decimal amounts of nutriment, vitamin, etc.
- type: Fix
- id: 6000
- time: '2024-02-22T00:19:50.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/25453
-- author: Whisper
- changes:
- - message: Dragon ichor when eating restores the dragon's blood.
- type: Add
- - message: Increased Xenomorph and Dragon blood level to 650u.
- type: Tweak
- id: 6001
- time: '2024-02-22T02:54:16.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/25442
-- author: Beck Thompson
- changes:
- - message: Radio jammer now uses 3 times less power.
- type: Tweak
- id: 6002
- time: '2024-02-22T07:32:43.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/25432
-- author: metalgearsloth
- changes:
- - message: Added handheld crew monitor back just for CMO.
- type: Add
- id: 6003
- time: '2024-02-22T11:00:35.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/25439
-- author: DrMelon
- changes:
- - message: Fixed incorrect job-specific Uplink items being given on occasion.
- type: Fix
- id: 6004
- time: '2024-02-22T11:03:44.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/23179
-- author: liltenhead
- changes:
- - message: Changed the syndicate assault borg to have a red flashlight.
- type: Tweak
- id: 6005
- time: '2024-02-22T11:15:10.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/25465
-- author: lzk228
- changes:
- - message: Fix some items becomes bigger after turning in trash.
- type: Fix
- id: 6006
- time: '2024-02-22T11:28:03.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/25461
-- author: ps3moira
- changes:
- - message: Added Large Wooden floors
- type: Add
- id: 6007
- time: '2024-02-22T11:59:41.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/25462
-- author: Whisper
- changes:
- - message: Fixed reagent slime ghost role description.
- type: Fix
- id: 6008
- time: '2024-02-22T12:18:46.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/25466
-- author: lzk228
- changes:
- - message: Galoshes are added to the Janidrobe.
- type: Tweak
- - message: Galoshes now make you slower.
- type: Tweak
- id: 6009
- time: '2024-02-23T01:05:11.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/25484
-- author: PJB3005
- changes:
- - message: sorting of departments and jobs has been made consistent in various menus.
- type: Tweak
- id: 6010
- time: '2024-02-23T04:04:44.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/25486
-- author: liltenhead
- changes:
- - message: Changed emergency welder's fuel count from 25 -> 50
- type: Tweak
- id: 6011
- time: '2024-02-23T06:53:39.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/25483
-- author: Vasilis
- changes:
- - message: Fixed a bug where the centcom official/any job that is not supposed to
- have a preference option appeared anyway.
- type: Fix
- id: 6012
- time: '2024-02-23T13:19:52.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/25496
-- author: Erisfiregamer1
- changes:
- - message: Fixed a typo when forcefeeding someone.
- type: Fix
- id: 6013
- time: '2024-02-24T01:45:02.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/25512
-- author: Beck Thompson
- changes:
- - message: The Fire Extinguishers safety can now only be toggled when in range.
- type: Fix
- id: 6014
- time: '2024-02-25T02:29:16.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/25534
-- author: ArchPigeon
- changes:
- - message: Removed the ability for command or any antag-safe role to be initial
- infected in zombie mode
- type: Remove
- id: 6015
- time: '2024-02-25T02:40:49.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/25529
-- author: PolterTzi
- changes:
- - message: Cargo ordering multiple crates in one order should work now.
- type: Fix
- id: 6016
- time: '2024-02-25T07:36:22.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/25518
- author: metalgearsloth
changes:
- message: Remove executions pending code rewrite.
@@ -3863,3 +3714,149 @@
id: 6496
time: '2024-04-29T13:12:30.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/27484
+- author: FungiFellow
+ changes:
+ - message: Syndi-Cats now have a Wideswing, 80% Explosion Resist, 6/6/15 Pierce/Slash/Structural
+ and step over glass shards with trained feline agility.
+ type: Tweak
+ id: 6497
+ time: '2024-04-29T17:09:30.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/27408
+- author: ShadowCommander
+ changes:
+ - message: Fixed microwave construction not creating a microwave on completion.
+ type: Fix
+ id: 6498
+ time: '2024-04-30T00:19:08.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/27500
+- author: lzk228
+ changes:
+ - message: Barozine is removed from hydroponics mutatuions.
+ type: Remove
+ id: 6499
+ time: '2024-04-30T03:01:38.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/27512
+- author: DogZeroX
+ changes:
+ - message: Changed the announcement of the immovable rod event.
+ type: Tweak
+ id: 6500
+ time: '2024-04-30T04:05:14.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/27515
+- author: DogZeroX
+ changes:
+ - message: Flares looped sound no longer have a massive range, and are much quieter.
+ type: Fix
+ id: 6501
+ time: '2024-04-30T06:49:35.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/27521
+- author: ERORR404V1
+ changes:
+ - message: Added chameleon projector in thief toolbox!
+ type: Add
+ id: 6502
+ time: '2024-04-30T12:14:06.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/27491
+- author: DamnFeds
+ changes:
+ - message: honkbot now uses a happy honk meal instead of box of hugs and clown's
+ rubber stamp. Honk!
+ type: Tweak
+ id: 6503
+ time: '2024-05-01T03:27:21.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/27535
+- author: Plykiya
+ changes:
+ - message: Inserting telecrystals no longer announces to everyone around you that
+ you inserted it.
+ type: Tweak
+ id: 6504
+ time: '2024-05-01T15:17:47.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/27585
+- author: Dezzzix
+ changes:
+ - message: Goldschlager empty bottle renamed to Gildlager empty bottle
+ type: Tweak
+ id: 6505
+ time: '2024-05-01T15:24:05.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/27581
+- author: FungiFellow
+ changes:
+ - message: Grilles now take Structural Damage
+ type: Tweak
+ id: 6506
+ time: '2024-05-01T22:23:42.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/27596
+- author: lzk228
+ changes:
+ - message: Immovable rod announce now happens at the end of event.
+ type: Tweak
+ id: 6507
+ time: '2024-05-01T22:26:22.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/27587
+- author: metalgearsloth
+ changes:
+ - message: Fix server performance dropping significantly.
+ type: Fix
+ id: 6508
+ time: '2024-05-02T00:18:38.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/27528
+- author: metalgearsloth
+ changes:
+ - message: Fix muzzle flash rotations.
+ type: Fix
+ - message: Fix large client performance drop.
+ type: Fix
+ id: 6509
+ time: '2024-05-02T02:40:07.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/27533
+- author: ElectroJr
+ changes:
+ - message: Fix gas analyzers not opening their UI when used in-hand.
+ type: Fix
+ id: 6510
+ time: '2024-05-02T06:00:01.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/27610
+- author: Plykiya
+ changes:
+ - message: Disarming a player now causes them to throw the disarmed item away from
+ them.
+ type: Tweak
+ id: 6511
+ time: '2024-05-02T12:32:47.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/27589
+- author: fujiwaranao
+ changes:
+ - message: Renault now has additional fox noises.
+ type: Add
+ id: 6512
+ time: '2024-05-02T12:35:11.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/27578
+- author: Doc-Michael
+ changes:
+ - message: CMO's Lab coat is now more resistant to chemical spills and minor cuts
+ type: Tweak
+ id: 6513
+ time: '2024-05-02T12:37:12.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/27551
+- author: Vasilis
+ changes:
+ - message: Removed airtight flaps from the construction menu.
+ type: Remove
+ id: 6514
+ time: '2024-05-02T14:49:54.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/27619
+- author: Lamrr
+ changes:
+ - message: Wine and beer bottles can now be inserted into the booze dispenser.
+ type: Fix
+ id: 6515
+ time: '2024-05-02T16:17:36.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/27626
+- author: deltanedas
+ changes:
+ - message: "Ducky slippers now make you waddle. \U0001F986\U0001F986"
+ type: Tweak
+ id: 6516
+ time: '2024-05-02T17:09:38.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/27628
diff --git a/Resources/Credits/Patrons.yml b/Resources/Credits/Patrons.yml
index f7e8df9bc0..3423e797ab 100644
--- a/Resources/Credits/Patrons.yml
+++ b/Resources/Credits/Patrons.yml
@@ -276,8 +276,8 @@
Tier: Nuclear Operative
- Name: "Andrew"
Tier: Revolutionary
-- Name: "Jack"
- Tier: Syndicate Agent
+- Name: "Cooliano Rizzo"
+ Tier: Nuclear Operative
- Name: "Brandon Roughley"
Tier: Syndicate Agent
- Name: "Sean Lilly"
@@ -286,5 +286,37 @@
Tier: Revolutionary
- Name: "Hannah Dawson"
Tier: Syndicate Agent
+- Name: "Jake Huxell"
+ Tier: Syndicate Agent
- Name: "Godfiend"
Tier: Revolutionary
+- Name: "Jordon"
+ Tier: Revolutionary
+- Name: "Luna Rose"
+ Tier: Revolutionary
+- Name: "Ethan Maria"
+ Tier: Revolutionary
+- Name: "Robyn Pothagan"
+ Tier: Revolutionary
+- Name: "TheGungeonologist"
+ Tier: Revolutionary
+- Name: "Ryan Kelly"
+ Tier: Revolutionary
+- Name: "Jacob Scott"
+ Tier: Revolutionary
+- Name: "Matthias Bechtold"
+ Tier: Revolutionary
+- Name: "Joshua Meyer"
+ Tier: Nuclear Operative
+- Name: "Roxy Rirumi"
+ Tier: Revolutionary
+- Name: "Zero To template"
+ Tier: Nuclear Operative
+- Name: "Hectik"
+ Tier: Revolutionary
+- Name: "orange color"
+ Tier: Revolutionary
+- Name: "Kristy Denniss"
+ Tier: Nuclear Operative
+- Name: "Kerensky"
+ Tier: Revolutionary
diff --git a/Resources/Locale/en-US/chat/emotes.ftl b/Resources/Locale/en-US/chat/emotes.ftl
index 86d79ffe4f..e95cb2795d 100644
--- a/Resources/Locale/en-US/chat/emotes.ftl
+++ b/Resources/Locale/en-US/chat/emotes.ftl
@@ -31,30 +31,30 @@ chat-emote-name-snore = Snore
# Message
chat-emote-msg-scream = screams!
-chat-emote-msg-laugh = laughs
-chat-emote-msg-honk = honks
-chat-emote-msg-sigh = sighs
-chat-emote-msg-whistle = whistle
-chat-emote-msg-crying = crying
-chat-emote-msg-squish = squishing
+chat-emote-msg-laugh = laughs.
+chat-emote-msg-honk = honks.
+chat-emote-msg-sigh = sighs.
+chat-emote-msg-whistle = whistles.
+chat-emote-msg-crying = cries.
+chat-emote-msg-squish = squishes.
chat-emote-msg-chitter = chitters.
chat-emote-msg-squeak = squeaks.
-chat-emote-msg-click = click.
+chat-emote-msg-click = clicks.
chat-emote-msg-clap = claps!
-chat-emote-msg-snap = snaps fingers
-chat-emote-msg-salute = salute
+chat-emote-msg-snap = snaps {POSS-ADJ($entity)} fingers.
+chat-emote-msg-salute = salutes.
chat-emote-msg-deathgasp = seizes up and falls limp, {POSS-ADJ($entity)} eyes dead and lifeless...
+chat-emote-msg-deathgasp-monkey = lets out a faint chimper as {SUBJECT($entity)} collapses and stops moving...
chat-emote-msg-buzz = buzz!
chat-emote-msg-chirp = chirps!
chat-emote-msg-beep = beeps.
chat-emote-msg-chime = chimes.
chat-emote-msg-buzzestwo = buzzes twice.
chat-emote-msg-ping = pings.
-chat-emote-msg-sneeze = sneezes
-chat-emote-msg-cough = coughs
-chat-emote-msg-catmeow = meows
-chat-emote-msg-cathisses = hisses
-chat-emote-msg-monkeyscreeches = screeches
-chat-emote-msg-robotbeep = beeps
-chat-emote-msg-yawn = yawns
-chat-emote-msg-snore = snores
+chat-emote-msg-sneeze = sneezes.
+chat-emote-msg-cough = coughs.
+chat-emote-msg-catmeow = meows.
+chat-emote-msg-cathisses = hisses!
+chat-emote-msg-monkeyscreeches = screeches!
+chat-emote-msg-yawn = yawns.
+chat-emote-msg-snore = snores.
diff --git a/Resources/Locale/en-US/ghost/ghost-gui.ftl b/Resources/Locale/en-US/ghost/ghost-gui.ftl
index 909513e96c..40cd06743e 100644
--- a/Resources/Locale/en-US/ghost/ghost-gui.ftl
+++ b/Resources/Locale/en-US/ghost/ghost-gui.ftl
@@ -10,6 +10,7 @@ ghost-gui-toggle-hearing-popup-off = You can now only hear radio and nearby mess
ghost-target-window-title = Ghost Warp
ghost-target-window-current-button = Warp: {$name}
+ghost-target-window-warp-to-most-followed = Warp to Most Followed
ghost-roles-window-title = Ghost Roles
ghost-roles-window-request-role-button = Request
diff --git a/Resources/Locale/en-US/markings/reptilian.ftl b/Resources/Locale/en-US/markings/reptilian.ftl
index ddd0eae62f..470af07361 100644
--- a/Resources/Locale/en-US/markings/reptilian.ftl
+++ b/Resources/Locale/en-US/markings/reptilian.ftl
@@ -68,6 +68,9 @@ marking-LizardFrillsDivinity = Lizard Frills (Divinity)
marking-LizardFrillsBig-frills_big = Lizard Frills (Big)
marking-LizardFrillsBig = Lizard Frills (Big)
+marking-LizardFrillsNeckfull-frills_neckfull = Lizard Frills (Neckfull)
+marking-LizardFrillsNeckfull = Lizard Frills (Neckfull)
+
marking-LizardHornsDouble-horns_double = Lizard Horns (Double)
marking-LizardHornsDouble = Lizard Horns (Double)
@@ -104,4 +107,4 @@ marking-LizardChestBackspikes = Lizard Back spikes (Four)
marking-LizardSnoutSplotch = Lizard Snout (Splotch)
marking-LizardSnoutSplotch-snout_splotch_primary = Muzzle
-marking-LizardSnoutSplotch-snout_splotch_secondary = Snoot
\ No newline at end of file
+marking-LizardSnoutSplotch-snout_splotch_secondary = Snoot
diff --git a/Resources/Locale/en-US/preferences/loadout-groups.ftl b/Resources/Locale/en-US/preferences/loadout-groups.ftl
index a093a8463a..68a47cba19 100644
--- a/Resources/Locale/en-US/preferences/loadout-groups.ftl
+++ b/Resources/Locale/en-US/preferences/loadout-groups.ftl
@@ -36,6 +36,7 @@ loadout-group-librarian-jumpsuit = Librarian jumpsuit
loadout-group-lawyer-jumpsuit = Lawyer jumpsuit
loadout-group-lawyer-neck = Lawyer neck
+loadout-group-lawyer-backpack = Lawyer backpack
loadout-group-chaplain-head = Chaplain head
loadout-group-chaplain-mask = Chaplain mask
diff --git a/Resources/Locale/en-US/station-events/events/immovable-rod.ftl b/Resources/Locale/en-US/station-events/events/immovable-rod.ftl
index 06abcc85c3..1b0e0a478b 100644
--- a/Resources/Locale/en-US/station-events/events/immovable-rod.ftl
+++ b/Resources/Locale/en-US/station-events/events/immovable-rod.ftl
@@ -1 +1 @@
-station-event-immovable-rod-start-announcement = High velocity unidentified object is on a collision course with the station. Impact imminent.
+station-event-immovable-rod-start-announcement = What the fuck was that?!?
diff --git a/Resources/Locale/en-US/store/currency.ftl b/Resources/Locale/en-US/store/currency.ftl
index 5d7ed95935..ed28391531 100644
--- a/Resources/Locale/en-US/store/currency.ftl
+++ b/Resources/Locale/en-US/store/currency.ftl
@@ -1,4 +1,4 @@
-store-currency-inserted = {CAPITALIZE(THE($used))} is inserted into the {THE($target)}.
+store-currency-inserted = {CAPITALIZE(THE($used))} is inserted into {THE($target)}.
store-currency-war-boost-given = { CAPITALIZE($target) } starts buzzing
store-currency-inserted-implant = {CAPITALIZE(THE($used))} is inserted into your implant.
diff --git a/Resources/Locale/en-US/thief/backpack.ftl b/Resources/Locale/en-US/thief/backpack.ftl
index 31b87c6f02..90cb0031fb 100644
--- a/Resources/Locale/en-US/thief/backpack.ftl
+++ b/Resources/Locale/en-US/thief/backpack.ftl
@@ -15,9 +15,9 @@ thief-backpack-button-deselect = Select [X]
thief-backpack-category-chameleon-name = chameleon's kit
thief-backpack-category-chameleon-description =
- Includes a full set of clothing that contain
- chameleon technology, allowing you to disguise
- as pretty much anything on the station.
+ Includes a full set of clothing that contains chameleon technology,
+ Contains a chameleon projector to help disguise yourself as objects,
+ You'll be able to disguise yourself as almost anything and anyone.
thief-backpack-category-tools-name = bearcatcher's kit
thief-backpack-category-tools-description =
diff --git a/Resources/Prototypes/Catalog/thief_toolbox_sets.yml b/Resources/Prototypes/Catalog/thief_toolbox_sets.yml
index d0fbd277c8..ccf5160ffb 100644
--- a/Resources/Prototypes/Catalog/thief_toolbox_sets.yml
+++ b/Resources/Prototypes/Catalog/thief_toolbox_sets.yml
@@ -14,6 +14,7 @@
- ClothingEyesChameleon
- ClothingHeadsetChameleon
- ClothingShoesChameleon
+ - ChameleonProjector
- type: thiefBackpackSet
id: ToolsSet
diff --git a/Resources/Prototypes/Entities/Clothing/Belt/belts.yml b/Resources/Prototypes/Entities/Clothing/Belt/belts.yml
index c72a3f3120..2462d3d041 100644
--- a/Resources/Prototypes/Entities/Clothing/Belt/belts.yml
+++ b/Resources/Prototypes/Entities/Clothing/Belt/belts.yml
@@ -518,6 +518,8 @@
name: Sabre
insertVerbText: sheath-insert-verb
ejectVerbText: sheath-eject-verb
+ insertSound: /Audio/Items/sheath.ogg
+ ejectSound: /Audio/Items/unsheath.ogg
whitelist:
tags:
- CaptainSabre
diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/coats.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/coats.yml
index 7a78eca2ff..c8beb0ff8d 100644
--- a/Resources/Prototypes/Entities/Clothing/OuterClothing/coats.yml
+++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/coats.yml
@@ -225,7 +225,7 @@
parent: ClothingOuterStorageFoldableBase
id: ClothingOuterCoatLabCmo
name: chief medical officer's lab coat
- description: Bluer than the standard model.
+ description: Custom made blue lab coat for the Chief Medical Officer, offers improved protection against chemical spills and minor cuts
components:
- type: Sprite
sprite: Clothing/OuterClothing/Coats/labcoat_cmo.rsi
@@ -234,7 +234,9 @@
- type: Armor
modifiers:
coefficients:
- Caustic: 0.75
+ Slash: 0.95
+ Heat: 0.95
+ Caustic: 0.65
- type: entity
parent: [ClothingOuterStorageFoldableBaseOpened, ClothingOuterCoatLabCmo]
diff --git a/Resources/Prototypes/Entities/Clothing/Shoes/misc.yml b/Resources/Prototypes/Entities/Clothing/Shoes/misc.yml
index d1f6e083f4..d5a695c7c0 100644
--- a/Resources/Prototypes/Entities/Clothing/Shoes/misc.yml
+++ b/Resources/Prototypes/Entities/Clothing/Shoes/misc.yml
@@ -47,6 +47,8 @@
collection: FootstepDuck
params:
variation: 0.07
+ - type: WaddleWhenWorn
+ tumbleIntensity: 10 # smaller than clown shoes
- type: Construction
graph: ClothingShoeSlippersDuck
node: shoes
diff --git a/Resources/Prototypes/Entities/Debugging/tippy.yml b/Resources/Prototypes/Entities/Debugging/tippy.yml
index d8ba0fd51e..292cbed0f1 100644
--- a/Resources/Prototypes/Entities/Debugging/tippy.yml
+++ b/Resources/Prototypes/Entities/Debugging/tippy.yml
@@ -1,5 +1,6 @@
- type: entity
id: Tippy
+ noSpawn: true
components:
- type: Sprite
netsync: false
diff --git a/Resources/Prototypes/Entities/Mobs/Customization/Markings/reptilian.yml b/Resources/Prototypes/Entities/Mobs/Customization/Markings/reptilian.yml
index b7d9266327..5a52e09bf2 100644
--- a/Resources/Prototypes/Entities/Mobs/Customization/Markings/reptilian.yml
+++ b/Resources/Prototypes/Entities/Mobs/Customization/Markings/reptilian.yml
@@ -63,6 +63,15 @@
- sprite: Mobs/Customization/reptilian_parts.rsi
state: frills_hood_secondary
+- type: marking
+ id: LizardFrillsNeckfull
+ bodyPart: HeadSide
+ markingCategory: HeadSide
+ speciesRestriction: [Reptilian]
+ sprites:
+ - sprite: Mobs/Customization/reptilian_parts.rsi
+ state: frills_neckfull
+
- type: marking
id: LizardHornsAngler
bodyPart: HeadTop
diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml
index f8218023fb..3a0b4d2858 100644
--- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml
+++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml
@@ -433,7 +433,7 @@
- type: Speech
speechVerb: Moth
speechSounds: Squeak
- allowedEmotes: ['Chitter']
+ allowedEmotes: ['Chitter', 'Squeak']
- type: FaxableObject
insertingState: inserting_mothroach
- type: MothAccent
@@ -819,7 +819,7 @@
- type: Speech
speechVerb: Arachnid
speechSounds: Arachnid
- allowedEmotes: ['Click']
+ allowedEmotes: ['Click', 'Chitter']
- type: DamageStateVisuals
states:
Alive:
@@ -1155,6 +1155,8 @@
templateId: monkey
speciesId: monkey
- type: InventorySlots
+ - type: Deathgasp
+ prototype: MonkeyDeathgasp
- type: Cuffable
- type: RotationVisuals
defaultRotation: 90
@@ -1344,9 +1346,9 @@
speechVerb: Reptilian
- type: Vocal
sounds:
- Male: UnisexReptilian
- Female: UnisexReptilian
- Unsexed: UnisexReptilian
+ Male: MaleReptilian
+ Female: FemaleReptilian
+ Unsexed: MaleReptilian
- type: TypingIndicator
proto: lizard
- type: InteractionPopup
@@ -2236,7 +2238,7 @@
- type: Speech
speechVerb: Arachnid
speechSounds: Arachnid
- allowedEmotes: ['Click']
+ allowedEmotes: ['Click', 'Chitter']
- type: Vocal
sounds:
Male: UnisexArachnid
@@ -2525,7 +2527,7 @@
interactFailureString: petting-failure-generic
interactSuccessSpawn: EffectHearts
interactSuccessSound:
- path: /Audio/Animals/fox_squeak.ogg
+ collection: Fox
- type: Grammar
attributes:
gender: epicene
@@ -2758,6 +2760,11 @@
interactSuccessSound:
path: /Audio/Animals/cat_meow.ogg
- type: MeleeWeapon
+ altDisarm: false
+ angle: 0
+ animation: WeaponArcBite
+ soundHit:
+ path: /Audio/Effects/bite.ogg
damage:
types:
Piercing: 5
@@ -2813,19 +2820,22 @@
- type: AutoImplant
implants:
- MicroBombImplant
+ - type: ExplosionResistance
+ damageCoefficient: 0.2
- type: NpcFactionMember
factions:
- Syndicate
- type: MeleeWeapon
+ altDisarm: false
+ angle: 0
+ animation: WeaponArcBite
+ soundHit:
+ path: /Audio/Effects/bite.ogg
damage:
types:
- Piercing: 10
- Structural: 10
- - type: Insulated
- - type: Tag
- tags:
- - DoorBumpOpener
- - type: MovementAlwaysTouching
+ Slash: 6
+ Piercing: 6
+ Structural: 15
- type: entity
name: space cat
@@ -2846,7 +2856,13 @@
- type: Temperature
heatDamageThreshold: 423
coldDamageThreshold: 0
+ - type: Tag
+ tags:
+ - DoorBumpOpener
+ - type: MovementAlwaysTouching
- type: PressureImmunity
+ - type: StepTriggerImmune
+ - type: Insulated
- type: InteractionPopup
successChance: 0.7
interactSuccessString: petting-success-space-cat
diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml b/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml
index dab2860e28..23eb462db1 100644
--- a/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml
+++ b/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml
@@ -529,7 +529,7 @@
interactFailureString: petting-failure-generic
interactSuccessSpawn: EffectHearts
interactSuccessSound:
- path: /Audio/Animals/fox_squeak.ogg
+ collection: Fox
- type: Butcherable
spawned:
- id: FoodMeat
diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/slimes.yml b/Resources/Prototypes/Entities/Mobs/NPCs/slimes.yml
index e667b931de..00de018025 100644
--- a/Resources/Prototypes/Entities/Mobs/NPCs/slimes.yml
+++ b/Resources/Prototypes/Entities/Mobs/NPCs/slimes.yml
@@ -37,6 +37,7 @@
- type: Tag
tags:
- FootstepSound
+ - DoorBumpOpener
- type: Butcherable
butcheringType: Knife
spawned:
diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/space.yml b/Resources/Prototypes/Entities/Mobs/NPCs/space.yml
index 849cd83eba..7b321e80df 100644
--- a/Resources/Prototypes/Entities/Mobs/NPCs/space.yml
+++ b/Resources/Prototypes/Entities/Mobs/NPCs/space.yml
@@ -263,7 +263,7 @@
- type: Speech
speechVerb: Arachnid
speechSounds: Arachnid
- allowedEmotes: ['Click']
+ allowedEmotes: ['Click', 'Chitter']
- type: Vocal
sounds:
Male: UnisexArachnid
diff --git a/Resources/Prototypes/Entities/Mobs/Species/arachnid.yml b/Resources/Prototypes/Entities/Mobs/Species/arachnid.yml
index ec742e59b5..8b3c66d5dd 100644
--- a/Resources/Prototypes/Entities/Mobs/Species/arachnid.yml
+++ b/Resources/Prototypes/Entities/Mobs/Species/arachnid.yml
@@ -62,7 +62,7 @@
- type: Speech
speechVerb: Arachnid
speechSounds: Arachnid
- allowedEmotes: ['Click']
+ allowedEmotes: ['Click', 'Chitter']
- type: Vocal
sounds:
Male: UnisexArachnid
diff --git a/Resources/Prototypes/Entities/Mobs/Species/moth.yml b/Resources/Prototypes/Entities/Mobs/Species/moth.yml
index 33bb46b172..f2a0194b7a 100644
--- a/Resources/Prototypes/Entities/Mobs/Species/moth.yml
+++ b/Resources/Prototypes/Entities/Mobs/Species/moth.yml
@@ -22,7 +22,7 @@
accent: zombieMoth
- type: Speech
speechVerb: Moth
- allowedEmotes: ['Chitter']
+ allowedEmotes: ['Chitter', 'Squeak']
- type: TypingIndicator
proto: moth
- type: Butcherable
diff --git a/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml b/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml
index 6c01673322..f099ffdc6a 100644
--- a/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml
+++ b/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml
@@ -32,9 +32,9 @@
proto: lizard
- type: Vocal
sounds:
- Male: UnisexReptilian
- Female: UnisexReptilian
- Unsexed: UnisexReptilian
+ Male: MaleReptilian
+ Female: FemaleReptilian
+ Unsexed: MaleReptilian
- type: Damageable
damageContainer: Biological
damageModifierSet: Scale
diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_bottles.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_bottles.yml
index 73b1e06f9b..35ad43586b 100644
--- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_bottles.yml
+++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_bottles.yml
@@ -362,6 +362,7 @@
- type: Tag
tags:
- Wine
+ - DrinkBottle
- type: entity
parent: [DrinkBottleVisualsAll, DrinkBottleGlassBaseFull]
@@ -511,6 +512,7 @@
- type: Tag
tags:
- Wine
+ - DrinkBottle
# Small Bottles
@@ -536,6 +538,7 @@
- type: Tag
tags:
- Beer
+ - DrinkBottle
- type: entity
parent: [DrinkBottleVisualsAll, DrinkBottleGlassBaseFull]
@@ -559,7 +562,7 @@
- type: Tag
tags:
- Beer
-
+ - DrinkBottle
- type: entity
parent: [DrinkBottleVisualsAll, DrinkBottlePlasticBaseFull]
diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/trash_drinks.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/trash_drinks.yml
index a6b14d722d..9f94be9576 100644
--- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/trash_drinks.yml
+++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/trash_drinks.yml
@@ -212,12 +212,12 @@
- type: entity
- name: goldschlager bottle
+ name: gildlager bottle
parent: DrinkBottleBaseEmpty
- id: DrinkBottleGoldschlager
+ id: DrinkBottleGildlager
components:
- type: Sprite
- sprite: Objects/Consumable/TrashDrinks/goldschlagerbottle_empty.rsi
+ sprite: Objects/Consumable/TrashDrinks/gildlagerbottle_empty.rsi
- type: entity
diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/box.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/box.yml
index 6ce0c7a443..5d9ddca94d 100644
--- a/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/box.yml
+++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/box.yml
@@ -555,7 +555,6 @@
- type: Tag
tags:
- Trash
- - HappyHonk
- MimeHappyHonk
- type: Sprite
sprite: Objects/Storage/Happyhonk/mime.rsi
@@ -652,6 +651,10 @@
name: woeful cluwne meal
description: Nothing good can come of this.
components:
+ - type: Tag
+ tags:
+ - Trash
+ - CluwneHappyHonk
- type: Sprite
sprite: Objects/Storage/Happyhonk/cluwne.rsi
state: box
diff --git a/Resources/Prototypes/Entities/Objects/Devices/pinpointer.yml b/Resources/Prototypes/Entities/Objects/Devices/pinpointer.yml
index f5e46bbf54..b104b5787a 100644
--- a/Resources/Prototypes/Entities/Objects/Devices/pinpointer.yml
+++ b/Resources/Prototypes/Entities/Objects/Devices/pinpointer.yml
@@ -57,6 +57,11 @@
- type: Sprite
layers:
- state: pinpointer-syndicate
+ map: ["enum.PinpointerLayers.Base"]
+ - state: pinonnull
+ map: ["enum.PinpointerLayers.Screen"]
+ shader: unshaded
+ visible: false
- type: Icon
state: pinpointer-syndicate
- type: Pinpointer
@@ -72,6 +77,11 @@
- type: Sprite
layers:
- state: pinpointer-way
+ map: ["enum.PinpointerLayers.Base"]
+ - state: pinonnull
+ map: ["enum.PinpointerLayers.Screen"]
+ shader: unshaded
+ visible: false
- type: Icon
state: pinpointer-way
- type: Pinpointer
@@ -88,6 +98,11 @@
- type: Sprite
layers:
- state: pinpointer-station
+ map: ["enum.PinpointerLayers.Base"]
+ - state: pinonnull
+ map: ["enum.PinpointerLayers.Screen"]
+ shader: unshaded
+ visible: false
- type: Icon
state: pinpointer-station
- type: Pinpointer
diff --git a/Resources/Prototypes/Entities/Objects/Misc/chopsticks.yml b/Resources/Prototypes/Entities/Objects/Misc/chopsticks.yml
index 47cae456fa..ed49053f8a 100644
--- a/Resources/Prototypes/Entities/Objects/Misc/chopsticks.yml
+++ b/Resources/Prototypes/Entities/Objects/Misc/chopsticks.yml
@@ -23,9 +23,8 @@
- type: SpawnItemsOnUse
items:
- id: ChopSticks
+ sound:
+ path: /Audio/Effects/chopstickbreak.ogg
- type: Sprite
sprite: Objects/Misc/chopstick.rsi
state: paired
- - type: EmitSoundOnUse
- sound:
- path: /Audio/Effects/chopstickbreak.ogg
diff --git a/Resources/Prototypes/Entities/Objects/Tools/flare.yml b/Resources/Prototypes/Entities/Objects/Tools/flare.yml
index dbdb935b91..fdf5314863 100644
--- a/Resources/Prototypes/Entities/Objects/Tools/flare.yml
+++ b/Resources/Prototypes/Entities/Objects/Tools/flare.yml
@@ -20,7 +20,13 @@
fadeOutBehaviourID: fade_out
litSound:
path: /Audio/Items/Flare/flare_on.ogg
- loopedSound: /Audio/Items/Flare/flare_burn.ogg
+ loopedSound:
+ path: /Audio/Items/Flare/flare_burn.ogg
+ params:
+ loop: true
+ volume: -10
+ maxDistance: 5
+
- type: Sprite
sprite: Objects/Misc/flare.rsi
layers:
diff --git a/Resources/Prototypes/Entities/Structures/Walls/grille.yml b/Resources/Prototypes/Entities/Structures/Walls/grille.yml
index 11ada142fa..7be721b6f9 100644
--- a/Resources/Prototypes/Entities/Structures/Walls/grille.yml
+++ b/Resources/Prototypes/Entities/Structures/Walls/grille.yml
@@ -32,7 +32,7 @@
node: grille
deconstructionTarget: start
- type: Damageable
- damageContainer: Inorganic
+ damageContainer: StructuralInorganic
damageModifierSet: PerforatedMetallic
- type: PowerConsumer
showInMonitor: false
diff --git a/Resources/Prototypes/Entities/Structures/plastic_flaps.yml b/Resources/Prototypes/Entities/Structures/plastic_flaps.yml
index 4439c11d68..d418feefff 100644
--- a/Resources/Prototypes/Entities/Structures/plastic_flaps.yml
+++ b/Resources/Prototypes/Entities/Structures/plastic_flaps.yml
@@ -1,9 +1,7 @@
- type: entity
- id: PlasticFlapsClear
+ id: PlasticFlapsBase
parent: BaseStructureDynamic
- name: plastic flaps
- suffix: Clear
- description: Heavy duty, plastic flaps. Definitely can't get past those. No way.
+ abstract: true
placement:
mode: SnapgridCenter
components:
@@ -40,15 +38,23 @@
- type: IconSmooth
key: walls
mode: NoSprite
- - type: Construction
- graph: PlasticFlapsGraph
- node: plasticFlaps
- type: StaticPrice
price: 83
+- type: entity
+ id: PlasticFlapsClear
+ parent: PlasticFlapsBase
+ name: plastic flaps
+ suffix: Clear
+ description: Heavy duty, plastic flaps. Definitely can't get past those. No way.
+ components:
+ - type: Construction
+ graph: PlasticFlapsGraph
+ node: plasticFlaps
+
- type: entity
id: PlasticFlapsOpaque
- parent: PlasticFlapsClear
+ parent: PlasticFlapsBase
name: plastic flaps
suffix: Opaque
description: Heavy duty, plastic flaps. Definitely can't get past those. No way.
@@ -72,7 +78,7 @@
- type: entity
id: PlasticFlapsAirtightClear
- parent: PlasticFlapsClear
+ parent: PlasticFlapsBase
name: airtight plastic flaps
suffix: Airtight, Clear
description: Heavy duty, slightly stronger, airtight plastic flaps. Definitely can't get past those. No way.
@@ -86,15 +92,12 @@
- !type:DoActsBehavior
acts: ["Destruction"]
- type: Airtight
- - type: Construction
- graph: PlasticFlapsGraph
- node: airtightFlaps
- type: StaticPrice
price: 100
- type: entity
id: PlasticFlapsAirtightOpaque
- parent: PlasticFlapsOpaque
+ parent: PlasticFlapsBase
name: airtight plastic flaps
suffix: Airtight, Opaque
description: Heavy duty, slightly stronger, airtight plastic flaps. Definitely can't get past those. No way.
@@ -108,8 +111,5 @@
- !type:DoActsBehavior
acts: ["Destruction"]
- type: Airtight
- - type: Construction
- graph: PlasticFlapsGraph
- node: airtightopaqueFlaps
- type: StaticPrice
price: 100
diff --git a/Resources/Prototypes/GameRules/events.yml b/Resources/Prototypes/GameRules/events.yml
index e744545fd1..afc3a10cbd 100644
--- a/Resources/Prototypes/GameRules/events.yml
+++ b/Resources/Prototypes/GameRules/events.yml
@@ -476,11 +476,11 @@
noSpawn: true
components:
- type: StationEvent
- startAnnouncement: station-event-immovable-rod-start-announcement
- startAudio:
+ endAnnouncement: station-event-immovable-rod-start-announcement
+ endAudio:
path: /Audio/Announcements/attention.ogg
weight: 5
- duration: 1
+ duration: 25
earliestStart: 45
minimumPlayers: 20
- type: ImmovableRodRule
diff --git a/Resources/Prototypes/GameRules/variation.yml b/Resources/Prototypes/GameRules/variation.yml
index 7424fc2854..2884d5f9d6 100644
--- a/Resources/Prototypes/GameRules/variation.yml
+++ b/Resources/Prototypes/GameRules/variation.yml
@@ -24,8 +24,8 @@
components:
- type: WallReplaceVariationPass
- type: EntityReplaceVariationPass
- entitiesPerReplacementAverage: 10
- entitiesPerReplacementStdDev: 2
+ entitiesPerReplacementAverage: 50
+ entitiesPerReplacementStdDev: 10
replacements:
- id: WallSolidRust
@@ -36,8 +36,8 @@
components:
- type: ReinforcedWallReplaceVariationPass
- type: EntityReplaceVariationPass
- entitiesPerReplacementAverage: 12
- entitiesPerReplacementStdDev: 2
+ entitiesPerReplacementAverage: 50
+ entitiesPerReplacementStdDev: 10
replacements:
- id: WallReinforcedRust
diff --git a/Resources/Prototypes/Hydroponics/mutations.yml b/Resources/Prototypes/Hydroponics/mutations.yml
index 17617f5ee3..6108278a4a 100644
--- a/Resources/Prototypes/Hydroponics/mutations.yml
+++ b/Resources/Prototypes/Hydroponics/mutations.yml
@@ -6,7 +6,6 @@
reagents:
- Omnizine
- Nocturine
- - Barozine
- Lexorin
- Honk
- BuzzochloricBees
diff --git a/Resources/Prototypes/Loadouts/Jobs/Civilian/lawyer.yml b/Resources/Prototypes/Loadouts/Jobs/Civilian/lawyer.yml
index 00be124430..5edd3ecf76 100644
--- a/Resources/Prototypes/Loadouts/Jobs/Civilian/lawyer.yml
+++ b/Resources/Prototypes/Loadouts/Jobs/Civilian/lawyer.yml
@@ -97,4 +97,32 @@
- type: startingGear
id: LawyerNeck
equipment:
- neck: ClothingNeckLawyerbadge
\ No newline at end of file
+ neck: ClothingNeckLawyerbadge
+
+# Backpack
+- type: loadout
+ id: LawyerBackpack
+ equipment: LawyerBackpack
+
+- type: startingGear
+ id: LawyerBackpack
+ equipment:
+ back: ClothingBackpackLawyerFilled
+
+- type: loadout
+ id: LawyerSatchel
+ equipment: LawyerSatchel
+
+- type: startingGear
+ id: LawyerSatchel
+ equipment:
+ back: ClothingBackpackSatchelLawyerFilled
+
+- type: loadout
+ id: LawyerDuffel
+ equipment: LawyerDuffel
+
+- type: startingGear
+ id: LawyerDuffel
+ equipment:
+ back: ClothingBackpackDuffelLawyerFilled
diff --git a/Resources/Prototypes/Loadouts/loadout_groups.yml b/Resources/Prototypes/Loadouts/loadout_groups.yml
index acec697da2..e3313bff44 100644
--- a/Resources/Prototypes/Loadouts/loadout_groups.yml
+++ b/Resources/Prototypes/Loadouts/loadout_groups.yml
@@ -239,6 +239,14 @@
loadouts:
- LawyerNeck
+- type: loadoutGroup
+ id: LawyerBackpack
+ name: loadout-group-lawyer-backpack
+ loadouts:
+ - LawyerBackpack
+ - LawyerSatchel
+ - LawyerDuffel
+
- type: loadoutGroup
id: ChaplainHead
name: loadout-group-chaplain-head
diff --git a/Resources/Prototypes/Loadouts/role_loadouts.yml b/Resources/Prototypes/Loadouts/role_loadouts.yml
index a5aeda58b5..5bc6fc4572 100644
--- a/Resources/Prototypes/Loadouts/role_loadouts.yml
+++ b/Resources/Prototypes/Loadouts/role_loadouts.yml
@@ -75,7 +75,7 @@
groups:
- LawyerNeck
- LawyerJumpsuit
- - CommonBackpack
+ - LawyerBackpack
- Glasses
- Trinkets
diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/structures/plastic_flaps.yml b/Resources/Prototypes/Recipes/Construction/Graphs/structures/plastic_flaps.yml
index 776c1491a6..781dd4aa87 100644
--- a/Resources/Prototypes/Recipes/Construction/Graphs/structures/plastic_flaps.yml
+++ b/Resources/Prototypes/Recipes/Construction/Graphs/structures/plastic_flaps.yml
@@ -33,16 +33,6 @@
- tool: Welding
doAfter: 5
- - to: airtightFlaps
- completed:
- - !type:SnapToGrid { }
- steps:
- - material: Plastic
- amount: 5
- doAfter: 5
- - tool: Screwing
- doAfter: 5
-
- node: opaqueFlaps
entity: PlasticFlapsOpaque
edges:
@@ -54,44 +44,3 @@
steps:
- tool: Anchoring
doAfter: 10
-
- - to: airtightopaqueFlaps
- completed:
- - !type:SnapToGrid { }
- steps:
- - material: Plastic
- amount: 5
- doAfter: 5
- - tool: Screwing
- doAfter: 5
-
- - node: airtightFlaps
- entity: PlasticFlapsAirtightClear
- edges:
- - to: plasticFlaps
- completed:
- - !type:SpawnPrototype
- prototype: SheetPlastic
- amount: 5
- steps:
- - tool: Screwing
- doAfter: 10
-
- - to: airtightopaqueFlaps #test
- completed:
- - !type:SnapToGrid { }
- steps:
- - tool: Welding
- doAfter: 5
-
- - node: airtightopaqueFlaps
- entity: PlasticFlapsAirtightOpaque
- edges:
- - to: opaqueFlaps
- completed:
- - !type:SpawnPrototype
- prototype: SheetPlastic
- amount: 5
- steps:
- - tool: Screwing
- doAfter: 10
diff --git a/Resources/Prototypes/Recipes/Construction/structures.yml b/Resources/Prototypes/Recipes/Construction/structures.yml
index 46f61807f3..86c0002996 100644
--- a/Resources/Prototypes/Recipes/Construction/structures.yml
+++ b/Resources/Prototypes/Recipes/Construction/structures.yml
@@ -1625,23 +1625,6 @@
conditions:
- !type:TileNotBlocked
-- type: construction
- name: airtight plastic flaps
- id: PlasticFlapsAirtight
- graph: PlasticFlapsGraph
- startNode: start
- targetNode: airtightFlaps
- category: construction-category-structures
- placementMode: SnapgridCenter
- description: An airtight plastic flap to let items through and keep people out.
- objectType: Structure
- canBuildInImpassable: false
- icon:
- sprite: Structures/plastic_flaps.rsi
- state: plasticflaps
- conditions:
- - !type:TileNotBlocked
-
- type: construction
name: opaque plastic flaps
id: PlasticFlapsOpaque
@@ -1659,23 +1642,6 @@
conditions:
- !type:TileNotBlocked
-- type: construction
- name: airtight opaque plastic flaps
- id: PlasticFlapsAirtightOpaque
- graph: PlasticFlapsGraph
- startNode: start
- targetNode: airtightopaqueFlaps
- category: construction-category-structures
- placementMode: SnapgridCenter
- description: An opaque, airtight plastic flap to let items through and keep people out.
- objectType: Structure
- canBuildInImpassable: false
- icon:
- sprite: Structures/plastic_flaps.rsi
- state: plasticflaps
- conditions:
- - !type:TileNotBlocked
-
- type: construction
name: bananium clown statue
id: BananiumClownStatue
diff --git a/Resources/Prototypes/Recipes/Crafting/Graphs/bots/honkbot.yml b/Resources/Prototypes/Recipes/Crafting/Graphs/bots/honkbot.yml
index ff3f6d2e2a..6806aacc24 100644
--- a/Resources/Prototypes/Recipes/Crafting/Graphs/bots/honkbot.yml
+++ b/Resources/Prototypes/Recipes/Crafting/Graphs/bots/honkbot.yml
@@ -6,17 +6,11 @@
edges:
- to: bot
steps:
- - tag: BoxHug
+ - tag: HappyHonk
icon:
- sprite: Objects/Storage/boxes.rsi
- state: box_hug
- name: box of hugs
- - tag: ClownRubberStamp
- icon:
- sprite: Objects/Misc/stamps.rsi
- state: stamp-clown
- name: clown's rubber stamp
- doAfter: 2
+ sprite: Objects/Storage/Happyhonk/clown.rsi
+ state: box
+ name: happy honk meal
- tag: BikeHorn
icon:
sprite: Objects/Fun/bikehorn.rsi
@@ -45,21 +39,15 @@
edges:
- to: bot
steps:
- - tag: HappyHonk
+ - tag: CluwneHappyHonk
icon:
- sprite: Objects/Storage/Happyhonk/clown.rsi
+ sprite: Objects/Storage/Happyhonk/cluwne.rsi
state: box
- name: happy honk meal
- - tag: ClownRubberStamp
- icon:
- sprite: Objects/Misc/stamps.rsi
- state: stamp-clown
- name: clown's rubber stamp
- doAfter: 2
+ name: woeful cluwne meal
- tag: CluwneHorn
icon:
- sprite: Objects/Fun/cluwnehorn.rsi
- state: icon
+ sprite: Objects/Fun/cluwnehorn.rsi
+ state: icon
name: broken bike horn
doAfter: 2
- tag: ProximitySensor
diff --git a/Resources/Prototypes/SoundCollections/fox.yml b/Resources/Prototypes/SoundCollections/fox.yml
new file mode 100644
index 0000000000..912ae24e9a
--- /dev/null
+++ b/Resources/Prototypes/SoundCollections/fox.yml
@@ -0,0 +1,18 @@
+- type: soundCollection
+ id: Fox
+ files:
+ - /Audio/Animals/fox_squeak.ogg
+ - /Audio/Animals/fox1.ogg
+ - /Audio/Animals/fox2.ogg
+ - /Audio/Animals/fox3.ogg
+ - /Audio/Animals/fox4.ogg
+ - /Audio/Animals/fox5.ogg
+ - /Audio/Animals/fox6.ogg
+ - /Audio/Animals/fox7.ogg
+ - /Audio/Animals/fox8.ogg
+ - /Audio/Animals/fox9.ogg
+ - /Audio/Animals/fox10.ogg
+ - /Audio/Animals/fox11.ogg
+ - /Audio/Animals/fox12.ogg
+ - /Audio/Animals/fox13.ogg
+ - /Audio/Animals/fox14.ogg
diff --git a/Resources/Prototypes/Voice/disease_emotes.yml b/Resources/Prototypes/Voice/disease_emotes.yml
index c29d6dd017..54330133d7 100644
--- a/Resources/Prototypes/Voice/disease_emotes.yml
+++ b/Resources/Prototypes/Voice/disease_emotes.yml
@@ -41,7 +41,7 @@
id: RobotBeep
name: chat-emote-name-robotbeep
category: Vocal
- chatMessages: ["chat-emote-msg-robotbeep"]
+ chatMessages: ["chat-emote-msg-beep"]
- type: emote
id: Yawn
diff --git a/Resources/Prototypes/Voice/speech_emote_sounds.yml b/Resources/Prototypes/Voice/speech_emote_sounds.yml
index 61c951dca9..e86b05f4c8 100644
--- a/Resources/Prototypes/Voice/speech_emote_sounds.yml
+++ b/Resources/Prototypes/Voice/speech_emote_sounds.yml
@@ -72,7 +72,7 @@
collection: Weh
- type: emoteSounds
- id: UnisexReptilian
+ id: MaleReptilian
params:
variation: 0.125
sounds:
@@ -89,6 +89,24 @@
Weh:
collection: Weh
+- type: emoteSounds
+ id: FemaleReptilian
+ params:
+ variation: 0.125
+ sounds:
+ Scream:
+ path: /Audio/Voice/Reptilian/reptilian_scream.ogg
+ Laugh:
+ path: /Audio/Animals/lizard_happy.ogg
+ Honk:
+ collection: BikeHorn
+ Whistle:
+ collection: Whistles
+ Crying:
+ collection: FemaleCry
+ Weh:
+ collection: Weh
+
- type: emoteSounds
id: MaleSlime
sounds:
diff --git a/Resources/Prototypes/Voice/speech_emotes.yml b/Resources/Prototypes/Voice/speech_emotes.yml
index a859a14c2b..29a09c03cb 100644
--- a/Resources/Prototypes/Voice/speech_emotes.yml
+++ b/Resources/Prototypes/Voice/speech_emotes.yml
@@ -348,6 +348,12 @@
chatTriggers:
- deathgasp
+- type: emote
+ id: MonkeyDeathgasp
+ name: chat-emote-name-deathgasp
+ icon: Interface/Actions/scream.png
+ chatMessages: ["chat-emote-msg-deathgasp-monkey"]
+
- type: emote
id: Buzz
name: chat-emote-name-buzz
diff --git a/Resources/Prototypes/XenoArch/Effects/normal_effects.yml b/Resources/Prototypes/XenoArch/Effects/normal_effects.yml
index fae280bfba..f2723e5369 100644
--- a/Resources/Prototypes/XenoArch/Effects/normal_effects.yml
+++ b/Resources/Prototypes/XenoArch/Effects/normal_effects.yml
@@ -109,7 +109,7 @@
components:
- type: PointLight
radius: 8
- energy: 25
+ energy: 10
color: "#daa3fd"
- type: TriggerArtifact
- type: FlashOnTrigger
diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml
index f947332764..3424d5a4e5 100644
--- a/Resources/Prototypes/tags.yml
+++ b/Resources/Prototypes/tags.yml
@@ -400,6 +400,9 @@
- type: Tag
id: ClownSuit
+- type: Tag
+ id: CluwneHappyHonk
+
- type: Tag
id: CluwneHorn
diff --git a/Resources/Textures/Clothing/Under/Socks/coder.rsi/equipped-FEET.png b/Resources/Textures/Clothing/Under/Socks/coder.rsi/equipped-FEET.png
index 0fea622063..4bb67f166d 100644
Binary files a/Resources/Textures/Clothing/Under/Socks/coder.rsi/equipped-FEET.png and b/Resources/Textures/Clothing/Under/Socks/coder.rsi/equipped-FEET.png differ
diff --git a/Resources/Textures/Clothing/Under/Socks/coder.rsi/meta.json b/Resources/Textures/Clothing/Under/Socks/coder.rsi/meta.json
index 194b8c4f0f..1bb04ab6eb 100644
--- a/Resources/Textures/Clothing/Under/Socks/coder.rsi/meta.json
+++ b/Resources/Textures/Clothing/Under/Socks/coder.rsi/meta.json
@@ -1,7 +1,7 @@
{
"version": 1,
"license": "CC-BY-SA-3.0",
- "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/c838ba21dae97db345e0113f99596decd1d66039",
+ "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/c838ba21dae97db345e0113f99596decd1d66039, equipped-FEET modified by Psychpsyo",
"size": {
"x": 32,
"y": 32
diff --git a/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/frills_neckfull.png b/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/frills_neckfull.png
new file mode 100644
index 0000000000..dfbe573096
Binary files /dev/null and b/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/frills_neckfull.png differ
diff --git a/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/meta.json b/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/meta.json
index de7b26ad6c..3770a771d8 100644
--- a/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/meta.json
+++ b/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/meta.json
@@ -1,7 +1,7 @@
{
"version": 1,
"license": "CC-BY-SA-3.0",
- "copyright": "https://github.com/Skyrat-SS13/Skyrat-tg/tree/40e3cdbb15b8bc0d5ef2fb46133adf805bda5297, while Argali, Ayrshire, Myrsore and Bighorn are drawn by Ubaser, and Kobold Ears are drawn by Pigeonpeas. Body_underbelly made by Nairod(github) for SS14. Large drawn by Ubaser. Wagging tail by SonicDC. Splotch modified from Sharp by KittenColony(github)",
+ "copyright": "https://github.com/Skyrat-SS13/Skyrat-tg/tree/40e3cdbb15b8bc0d5ef2fb46133adf805bda5297, while Argali, Ayrshire, Myrsore and Bighorn are drawn by Ubaser, and Kobold Ears are drawn by Pigeonpeas. Body_underbelly made by Nairod(github) for SS14. Large drawn by Ubaser. Wagging tail by SonicDC. Splotch modified from Sharp by KittenColony(github). Frills neckfull come from: https://github.com/Bubberstation/Bubberstation/commit/8bc6b83404803466a560b694bf22ef3c0ac266a2",
"size": {
"x": 32,
"y": 32
@@ -87,391 +87,391 @@
"name": "tail_smooth_wagging_primary",
"directions": 4,
"delays": [
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ],
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ],
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ],
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ]
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
]
},
{
"name": "tail_smooth_wagging_secondary",
"directions": 4,
"delays": [
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ],
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ],
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ],
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ]
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
]
},
{
- "name": "tail_dtiger_wagging",
- "directions": 4,
- "delays": [
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ],
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ],
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ],
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ]
+ "name": "tail_dtiger_wagging",
+ "directions": 4,
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
]
+ ]
},
{
- "name": "tail_ltiger_wagging",
- "directions": 4,
- "delays": [
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ],
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ],
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ],
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ]
+ "name": "tail_ltiger_wagging",
+ "directions": 4,
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
]
+ ]
},
{
- "name": "tail_spikes_wagging",
- "directions": 4,
- "delays": [
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ],
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ],
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ],
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ]
+ "name": "tail_spikes_wagging",
+ "directions": 4,
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
]
+ ]
},
{
"name": "snout_round",
@@ -525,19 +525,19 @@
"name": "frills_divinity",
"directions": 4
},
- {
+ {
"name": "horns_double",
"directions": 4
},
- {
+ {
"name": "frills_axolotl",
"directions": 4
},
- {
+ {
"name": "frills_hood_primary",
"directions": 4
},
- {
+ {
"name": "frills_hood_secondary",
"directions": 4
},
@@ -548,59 +548,59 @@
{
"name": "body_tiger",
"directions": 4
- },
- {
- "name": "head_tiger",
- "directions": 4
- },
- {
- "name": "l_arm_tiger",
- "directions": 4
- },
- {
- "name": "l_leg_tiger",
- "directions": 4
- },
- {
- "name": "r_arm_tiger",
- "directions": 4
- },
- {
- "name": "horns_argali",
- "directions": 4
- },
- {
- "name": "horns_ayrshire",
- "directions": 4
- },
- {
- "name": "horns_myrsore",
- "directions": 4
- },
- {
- "name": "horns_bighorn",
- "directions": 4
- },
- {
- "name": "horns_kobold_ears",
- "directions": 4
- },
- {
- "name": "r_leg_tiger",
- "directions": 4
},
- {
- "name": "horns_floppy_kobold_ears",
- "directions": 4
- },
+ {
+ "name": "head_tiger",
+ "directions": 4
+ },
+ {
+ "name": "l_arm_tiger",
+ "directions": 4
+ },
+ {
+ "name": "l_leg_tiger",
+ "directions": 4
+ },
+ {
+ "name": "r_arm_tiger",
+ "directions": 4
+ },
+ {
+ "name": "horns_argali",
+ "directions": 4
+ },
+ {
+ "name": "horns_ayrshire",
+ "directions": 4
+ },
+ {
+ "name": "horns_myrsore",
+ "directions": 4
+ },
+ {
+ "name": "horns_bighorn",
+ "directions": 4
+ },
+ {
+ "name": "horns_kobold_ears",
+ "directions": 4
+ },
+ {
+ "name": "r_leg_tiger",
+ "directions": 4
+ },
+ {
+ "name": "horns_floppy_kobold_ears",
+ "directions": 4
+ },
{
"name": "body_underbelly",
"directions": 4
- },
- {
- "name": "body_backspikes",
- "directions": 4
- },
+ },
+ {
+ "name": "body_backspikes",
+ "directions": 4
+ },
{
"name": "snout_splotch_primary",
"directions": 4
@@ -608,6 +608,10 @@
{
"name": "snout_splotch_secondary",
"directions": 4
+ },
+ {
+ "name": "frills_neckfull",
+ "directions": 4
}
]
-}
+}
\ No newline at end of file
diff --git a/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/snout_splotch_primary.png b/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/snout_splotch_primary.png
index 0098822db9..850b985e5d 100644
Binary files a/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/snout_splotch_primary.png and b/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/snout_splotch_primary.png differ
diff --git a/Resources/Textures/Objects/Consumable/TrashDrinks/goldschlagerbottle_empty.rsi/icon.png b/Resources/Textures/Objects/Consumable/TrashDrinks/gildlagerbottle_empty.rsi/icon.png
similarity index 100%
rename from Resources/Textures/Objects/Consumable/TrashDrinks/goldschlagerbottle_empty.rsi/icon.png
rename to Resources/Textures/Objects/Consumable/TrashDrinks/gildlagerbottle_empty.rsi/icon.png
diff --git a/Resources/Textures/Objects/Consumable/TrashDrinks/goldschlagerbottle_empty.rsi/meta.json b/Resources/Textures/Objects/Consumable/TrashDrinks/gildlagerbottle_empty.rsi/meta.json
similarity index 100%
rename from Resources/Textures/Objects/Consumable/TrashDrinks/goldschlagerbottle_empty.rsi/meta.json
rename to Resources/Textures/Objects/Consumable/TrashDrinks/gildlagerbottle_empty.rsi/meta.json
diff --git a/Resources/migration.yml b/Resources/migration.yml
index 84203370e9..40154d74af 100644
--- a/Resources/migration.yml
+++ b/Resources/migration.yml
@@ -332,3 +332,6 @@ WeaponRifleLecterRubber: WeaponRifleLecter
GlassBoxLaserBroken: GlassBoxBroken
ReinforcementRadioSyndicateMonkey: ReinforcementRadioSyndicateAncestor
ReinforcementRadioSyndicateMonkeyNukeops: ReinforcementRadioSyndicateAncestorNukeops
+
+# 2024-05-01
+DrinkBottleGoldschlager: DrinkBottleGildlager
diff --git a/RobustToolbox b/RobustToolbox
index 8550056e68..7cb3aeccc2 160000
--- a/RobustToolbox
+++ b/RobustToolbox
@@ -1 +1 @@
-Subproject commit 8550056e685e6b758f460c18f5863b37787d3093
+Subproject commit 7cb3aeccc23a894b149b4547e5fecb399c8c507f