Merge remote-tracking branch 'upstream/master' into ed-05-08-2024-upstream
# Conflicts: # Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs
This commit is contained in:
@@ -93,6 +93,6 @@ public sealed class ClientAlertsSystem : AlertsSystem
|
||||
|
||||
public void AlertClicked(ProtoId<AlertPrototype> alertType)
|
||||
{
|
||||
RaiseNetworkEvent(new ClickAlertEvent(alertType));
|
||||
RaisePredictiveEvent(new ClickAlertEvent(alertType));
|
||||
}
|
||||
}
|
||||
|
||||
10
Content.Client/Atmos/EntitySystems/GasMinerSystem.cs
Normal file
10
Content.Client/Atmos/EntitySystems/GasMinerSystem.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using Content.Shared.Atmos.EntitySystems;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Content.Client.Atmos.EntitySystems;
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed class GasMinerSystem : SharedGasMinerSystem
|
||||
{
|
||||
|
||||
}
|
||||
@@ -16,6 +16,7 @@ namespace Content.Client.Chat.UI
|
||||
[Dependency] private readonly IEyeManager _eyeManager = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] protected readonly IConfigurationManager ConfigManager = default!;
|
||||
private readonly SharedTransformSystem _transformSystem;
|
||||
|
||||
public enum SpeechType : byte
|
||||
{
|
||||
@@ -83,6 +84,7 @@ namespace Content.Client.Chat.UI
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
_senderEntity = senderEntity;
|
||||
_transformSystem = _entityManager.System<SharedTransformSystem>();
|
||||
|
||||
// Use text clipping so new messages don't overlap old ones being pushed up.
|
||||
RectClipContent = true;
|
||||
@@ -140,7 +142,7 @@ namespace Content.Client.Chat.UI
|
||||
}
|
||||
|
||||
var offset = (-_eyeManager.CurrentEye.Rotation).ToWorldVec() * -EntityVerticalOffset;
|
||||
var worldPos = xform.WorldPosition + offset;
|
||||
var worldPos = _transformSystem.GetWorldPosition(xform) + offset;
|
||||
|
||||
var lowerCenter = _eyeManager.WorldToScreen(worldPos) / UIScale;
|
||||
var screenPos = lowerCenter - new Vector2(ContentSize.X / 2, ContentSize.Y + _verticalOffsetAchieved);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Content.Client.Actions;
|
||||
using Content.Client.Mapping;
|
||||
using Content.Client.Markers;
|
||||
using JetBrains.Annotations;
|
||||
@@ -25,7 +26,7 @@ internal sealed class MappingClientSideSetupCommand : LocalizedCommands
|
||||
_entitySystemManager.GetEntitySystem<MarkerSystem>().MarkersVisible = true;
|
||||
_lightManager.Enabled = false;
|
||||
shell.ExecuteCommand("showsubfloorforever");
|
||||
_stateManager.RequestStateChange<MappingState>();
|
||||
_entitySystemManager.GetEntitySystem<ActionsSystem>().LoadActionAssignments("/mapping_actions.yml", false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ public sealed class ExplosionOverlay : Overlay
|
||||
[Dependency] private readonly IRobustRandom _robustRandom = default!;
|
||||
[Dependency] private readonly IEntityManager _entMan = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
private readonly SharedTransformSystem _transformSystem;
|
||||
private SharedAppearanceSystem _appearance;
|
||||
|
||||
public override OverlaySpace Space => OverlaySpace.WorldSpaceBelowFOV;
|
||||
@@ -26,6 +27,7 @@ public sealed class ExplosionOverlay : Overlay
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
_shader = _proto.Index<ShaderPrototype>("unshaded").Instance();
|
||||
_transformSystem = _entMan.System<SharedTransformSystem>();
|
||||
_appearance = appearanceSystem;
|
||||
}
|
||||
|
||||
@@ -68,7 +70,7 @@ public sealed class ExplosionOverlay : Overlay
|
||||
continue;
|
||||
|
||||
var xform = xforms.GetComponent(gridId);
|
||||
var (_, _, worldMatrix, invWorldMatrix) = xform.GetWorldPositionRotationMatrixWithInv(xforms);
|
||||
var (_, _, worldMatrix, invWorldMatrix) = _transformSystem.GetWorldPositionRotationMatrixWithInv(xform, xforms);
|
||||
|
||||
gridBounds = invWorldMatrix.TransformBox(worldBounds).Enlarged(grid.TileSize * 2);
|
||||
drawHandle.SetTransform(worldMatrix);
|
||||
|
||||
@@ -14,6 +14,7 @@ public sealed class PuddleOverlay : Overlay
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;
|
||||
private readonly PuddleDebugOverlaySystem _debugOverlaySystem;
|
||||
private readonly SharedTransformSystem _transformSystem;
|
||||
|
||||
private readonly Color _heavyPuddle = new(0, 255, 255, 50);
|
||||
private readonly Color _mediumPuddle = new(0, 150, 255, 50);
|
||||
@@ -29,6 +30,7 @@ public sealed class PuddleOverlay : Overlay
|
||||
_debugOverlaySystem = _entitySystemManager.GetEntitySystem<PuddleDebugOverlaySystem>();
|
||||
var cache = IoCManager.Resolve<IResourceCache>();
|
||||
_font = new VectorFont(cache.GetResource<FontResource>("/Fonts/NotoSans/NotoSans-Regular.ttf"), 8);
|
||||
_transformSystem = _entityManager.System<SharedTransformSystem>();
|
||||
}
|
||||
|
||||
protected override void Draw(in OverlayDrawArgs args)
|
||||
@@ -56,7 +58,7 @@ public sealed class PuddleOverlay : Overlay
|
||||
continue;
|
||||
|
||||
var gridXform = xformQuery.GetComponent(gridId);
|
||||
var (_, _, worldMatrix, invWorldMatrix) = gridXform.GetWorldPositionRotationMatrixWithInv(xformQuery);
|
||||
var (_, _, worldMatrix, invWorldMatrix) = _transformSystem.GetWorldPositionRotationMatrixWithInv(gridXform, xformQuery);
|
||||
gridBounds = invWorldMatrix.TransformBox(args.WorldBounds).Enlarged(mapGrid.TileSize * 2);
|
||||
drawHandle.SetTransform(worldMatrix);
|
||||
|
||||
@@ -89,7 +91,7 @@ public sealed class PuddleOverlay : Overlay
|
||||
continue;
|
||||
|
||||
var gridXform = xformQuery.GetComponent(gridId);
|
||||
var (_, _, matrix, invMatrix) = gridXform.GetWorldPositionRotationMatrixWithInv(xformQuery);
|
||||
var (_, _, matrix, invMatrix) = _transformSystem.GetWorldPositionRotationMatrixWithInv(gridXform, xformQuery);
|
||||
var gridBounds = invMatrix.TransformBox(args.WorldBounds).Enlarged(mapGrid.TileSize * 2);
|
||||
|
||||
foreach (var debugOverlayData in _debugOverlaySystem.GetData(gridId))
|
||||
|
||||
@@ -42,6 +42,7 @@ public sealed class DragDropSystem : SharedDragDropSystem
|
||||
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
|
||||
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
|
||||
|
||||
// how often to recheck possible targets (prevents calling expensive
|
||||
// check logic each update)
|
||||
@@ -89,7 +90,7 @@ public sealed class DragDropSystem : SharedDragDropSystem
|
||||
/// </summary>
|
||||
private bool _isReplaying;
|
||||
|
||||
private float _deadzone;
|
||||
public float Deadzone;
|
||||
|
||||
private DragState _state = DragState.NotDragging;
|
||||
|
||||
@@ -121,7 +122,7 @@ public sealed class DragDropSystem : SharedDragDropSystem
|
||||
|
||||
private void SetDeadZone(float deadZone)
|
||||
{
|
||||
_deadzone = deadZone;
|
||||
Deadzone = deadZone;
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
@@ -211,7 +212,7 @@ public sealed class DragDropSystem : SharedDragDropSystem
|
||||
|
||||
_draggedEntity = entity;
|
||||
_state = DragState.MouseDown;
|
||||
_mouseDownScreenPos = _inputManager.MouseScreenPosition;
|
||||
_mouseDownScreenPos = args.ScreenCoordinates;
|
||||
_mouseDownTime = 0;
|
||||
|
||||
// don't want anything else to process the click,
|
||||
@@ -239,8 +240,13 @@ public sealed class DragDropSystem : SharedDragDropSystem
|
||||
|
||||
if (TryComp<SpriteComponent>(_draggedEntity, out var draggedSprite))
|
||||
{
|
||||
var screenPos = _inputManager.MouseScreenPosition;
|
||||
// No _draggedEntity in null window (Happens in tests)
|
||||
if (!screenPos.IsValid)
|
||||
return;
|
||||
|
||||
// pop up drag shadow under mouse
|
||||
var mousePos = _eyeManager.PixelToMap(_inputManager.MouseScreenPosition);
|
||||
var mousePos = _eyeManager.PixelToMap(screenPos);
|
||||
_dragShadow = EntityManager.SpawnEntity("dragshadow", mousePos);
|
||||
var dragSprite = Comp<SpriteComponent>(_dragShadow.Value);
|
||||
dragSprite.CopyFrom(draggedSprite);
|
||||
@@ -517,6 +523,9 @@ public sealed class DragDropSystem : SharedDragDropSystem
|
||||
if (dropEv2.Handled)
|
||||
return dropEv2.CanDrop;
|
||||
|
||||
if (dropEv.Handled && dropEv.CanDrop)
|
||||
return true;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -530,7 +539,7 @@ public sealed class DragDropSystem : SharedDragDropSystem
|
||||
case DragState.MouseDown:
|
||||
{
|
||||
var screenPos = _inputManager.MouseScreenPosition;
|
||||
if ((_mouseDownScreenPos!.Value.Position - screenPos.Position).Length() > _deadzone)
|
||||
if ((_mouseDownScreenPos!.Value.Position - screenPos.Position).Length() > Deadzone)
|
||||
{
|
||||
StartDrag();
|
||||
}
|
||||
@@ -551,7 +560,7 @@ public sealed class DragDropSystem : SharedDragDropSystem
|
||||
if (Exists(_dragShadow))
|
||||
{
|
||||
var mousePos = _eyeManager.PixelToMap(_inputManager.MouseScreenPosition);
|
||||
Transform(_dragShadow.Value).WorldPosition = mousePos.Position;
|
||||
_transformSystem.SetWorldPosition(_dragShadow.Value, mousePos.Position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ public sealed class GridDraggingSystem : SharedGridDraggingSystem
|
||||
[Dependency] private readonly IInputManager _inputManager = default!;
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
[Dependency] private readonly InputSystem _inputSystem = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
|
||||
|
||||
public bool Enabled { get; set; }
|
||||
|
||||
@@ -62,11 +63,11 @@ public sealed class GridDraggingSystem : SharedGridDraggingSystem
|
||||
if (_dragging == null) return;
|
||||
|
||||
if (_lastMousePosition != null && TryComp(_dragging.Value, out TransformComponent? xform) &&
|
||||
TryComp<PhysicsComponent>(_dragging.Value, out var body) &&
|
||||
TryComp<PhysicsComponent>(_dragging.Value, out _) &&
|
||||
xform.MapID == _lastMousePosition.Value.MapId)
|
||||
{
|
||||
var tickTime = _gameTiming.TickPeriod;
|
||||
var distance = _lastMousePosition.Value.Position - xform.WorldPosition;
|
||||
var distance = _lastMousePosition.Value.Position - _transformSystem.GetWorldPosition(xform);
|
||||
RaiseNetworkEvent(new GridDragVelocityRequest()
|
||||
{
|
||||
Grid = GetNetEntity(_dragging.Value),
|
||||
|
||||
@@ -9,6 +9,7 @@ public sealed class HTNOverlay : Overlay
|
||||
{
|
||||
private readonly IEntityManager _entManager = default!;
|
||||
private readonly Font _font = default!;
|
||||
private readonly SharedTransformSystem _transformSystem;
|
||||
|
||||
public override OverlaySpace Space => OverlaySpace.ScreenSpace;
|
||||
|
||||
@@ -16,6 +17,7 @@ public sealed class HTNOverlay : Overlay
|
||||
{
|
||||
_entManager = entManager;
|
||||
_font = new VectorFont(resourceCache.GetResource<FontResource>("/Fonts/NotoSans/NotoSans-Regular.ttf"), 10);
|
||||
_transformSystem = _entManager.System<SharedTransformSystem>();
|
||||
}
|
||||
|
||||
protected override void Draw(in OverlayDrawArgs args)
|
||||
@@ -30,7 +32,7 @@ public sealed class HTNOverlay : Overlay
|
||||
if (string.IsNullOrEmpty(comp.DebugText) || xform.MapID != args.MapId)
|
||||
continue;
|
||||
|
||||
var worldPos = xform.WorldPosition;
|
||||
var worldPos = _transformSystem.GetWorldPosition(xform);
|
||||
|
||||
if (!args.WorldAABB.Contains(worldPos))
|
||||
continue;
|
||||
|
||||
@@ -81,10 +81,12 @@ public sealed class NPCSteeringOverlay : Overlay
|
||||
public override OverlaySpace Space => OverlaySpace.WorldSpace;
|
||||
|
||||
private readonly IEntityManager _entManager;
|
||||
private readonly SharedTransformSystem _transformSystem;
|
||||
|
||||
public NPCSteeringOverlay(IEntityManager entManager)
|
||||
{
|
||||
_entManager = entManager;
|
||||
_transformSystem = _entManager.System<SharedTransformSystem>();
|
||||
}
|
||||
|
||||
protected override void Draw(in OverlayDrawArgs args)
|
||||
@@ -96,7 +98,7 @@ public sealed class NPCSteeringOverlay : Overlay
|
||||
continue;
|
||||
}
|
||||
|
||||
var (worldPos, worldRot) = xform.GetWorldPositionRotation();
|
||||
var (worldPos, worldRot) = _transformSystem.GetWorldPositionRotation(xform);
|
||||
|
||||
if (!args.WorldAABB.Contains(worldPos))
|
||||
continue;
|
||||
|
||||
@@ -12,6 +12,7 @@ public sealed class NetworkConfiguratorLinkOverlay : Overlay
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
private readonly DeviceListSystem _deviceListSystem;
|
||||
private readonly SharedTransformSystem _transformSystem;
|
||||
|
||||
public Dictionary<EntityUid, Color> Colors = new();
|
||||
public EntityUid? Action;
|
||||
@@ -23,6 +24,7 @@ public sealed class NetworkConfiguratorLinkOverlay : Overlay
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
_deviceListSystem = _entityManager.System<DeviceListSystem>();
|
||||
_transformSystem = _entityManager.System<SharedTransformSystem>();
|
||||
}
|
||||
|
||||
protected override void Draw(in OverlayDrawArgs args)
|
||||
@@ -66,7 +68,7 @@ public sealed class NetworkConfiguratorLinkOverlay : Overlay
|
||||
continue;
|
||||
}
|
||||
|
||||
args.WorldHandle.DrawLine(sourceTransform.WorldPosition, linkTransform.WorldPosition, Colors[uid]);
|
||||
args.WorldHandle.DrawLine(_transformSystem.GetWorldPosition(sourceTransform), _transformSystem.GetWorldPosition(linkTransform), Colors[uid]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace Content.Client.NodeContainer
|
||||
private readonly IMapManager _mapManager;
|
||||
private readonly IInputManager _inputManager;
|
||||
private readonly IEntityManager _entityManager;
|
||||
private readonly SharedTransformSystem _transformSystem;
|
||||
|
||||
private readonly Dictionary<(int, int), NodeRenderData> _nodeIndex = new();
|
||||
private readonly Dictionary<EntityUid, Dictionary<Vector2i, List<(GroupData, NodeDatum)>>> _gridIndex = new ();
|
||||
@@ -46,6 +47,7 @@ namespace Content.Client.NodeContainer
|
||||
_mapManager = mapManager;
|
||||
_inputManager = inputManager;
|
||||
_entityManager = entityManager;
|
||||
_transformSystem = _entityManager.System<SharedTransformSystem>();
|
||||
|
||||
_font = cache.GetFont("/Fonts/NotoSans/NotoSans-Regular.ttf", 12);
|
||||
}
|
||||
@@ -146,7 +148,7 @@ namespace Content.Client.NodeContainer
|
||||
foreach (var (gridId, gridDict) in _gridIndex)
|
||||
{
|
||||
var grid = _entityManager.GetComponent<MapGridComponent>(gridId);
|
||||
var (_, _, worldMatrix, invMatrix) = _entityManager.GetComponent<TransformComponent>(gridId).GetWorldPositionRotationMatrixWithInv();
|
||||
var (_, _, worldMatrix, invMatrix) = _transformSystem.GetWorldPositionRotationMatrixWithInv(gridId);
|
||||
|
||||
var lCursorBox = invMatrix.TransformBox(cursorBox);
|
||||
foreach (var (pos, list) in gridDict)
|
||||
|
||||
@@ -23,6 +23,7 @@ public sealed class TargetOutlineSystem : EntitySystem
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
|
||||
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
|
||||
|
||||
private bool _enabled = false;
|
||||
|
||||
@@ -165,8 +166,8 @@ public sealed class TargetOutlineSystem : EntitySystem
|
||||
valid = _interactionSystem.InRangeUnobstructed(player, entity, Range);
|
||||
else if (Range >= 0)
|
||||
{
|
||||
var origin = Transform(player).WorldPosition;
|
||||
var target = Transform(entity).WorldPosition;
|
||||
var origin = _transformSystem.GetWorldPosition(player);
|
||||
var target = _transformSystem.GetWorldPosition(entity);
|
||||
valid = (origin - target).LengthSquared() <= Range;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ namespace Content.Client.Stealth;
|
||||
public sealed class StealthSystem : SharedStealthSystem
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _protoMan = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
|
||||
|
||||
private ShaderInstance _shader = default!;
|
||||
|
||||
@@ -81,7 +82,7 @@ public sealed class StealthSystem : SharedStealthSystem
|
||||
if (!parent.IsValid())
|
||||
return; // should never happen, but lets not kill the client.
|
||||
var parentXform = Transform(parent);
|
||||
var reference = args.Viewport.WorldToLocal(parentXform.WorldPosition);
|
||||
var reference = args.Viewport.WorldToLocal(_transformSystem.GetWorldPosition(parentXform));
|
||||
reference.X = -reference.X;
|
||||
var visibility = GetVisibility(uid, component);
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ namespace Content.Client.Tabletop
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
[Dependency] private readonly AppearanceSystem _appearance = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
|
||||
|
||||
// Time in seconds to wait until sending the location of a dragged entity to the server again
|
||||
private const float Delay = 1f / 10; // 10 Hz
|
||||
@@ -100,7 +101,7 @@ namespace Content.Client.Tabletop
|
||||
if (clampedCoords.Equals(MapCoordinates.Nullspace)) return;
|
||||
|
||||
// Move the entity locally every update
|
||||
EntityManager.GetComponent<TransformComponent>(_draggedEntity.Value).WorldPosition = clampedCoords.Position;
|
||||
_transformSystem.SetWorldPosition(_draggedEntity.Value, clampedCoords.Position);
|
||||
|
||||
// Increment total time passed
|
||||
_timePassed += frameTime;
|
||||
|
||||
@@ -15,7 +15,6 @@ public sealed class ViewportUIController : UIController
|
||||
[Dependency] private readonly IPlayerManager _playerMan = default!;
|
||||
[Dependency] private readonly IEntityManager _entMan = default!;
|
||||
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
|
||||
|
||||
public static readonly Vector2i ViewportSize = (EyeManager.PixelsPerMeter * 21, EyeManager.PixelsPerMeter * 15);
|
||||
public const int ViewportHeight = 15;
|
||||
private MainViewport? Viewport => UIManager.ActiveScreen?.GetWidget<MainViewport>();
|
||||
|
||||
@@ -236,7 +236,7 @@ public sealed partial class MeleeWeaponSystem
|
||||
private void UpdateEffects()
|
||||
{
|
||||
var query = EntityQueryEnumerator<TrackUserComponent, TransformComponent>();
|
||||
while (query.MoveNext(out var arcComponent, out var xform))
|
||||
while (query.MoveNext(out var uid, out var arcComponent, out var xform))
|
||||
{
|
||||
if (arcComponent.User == null)
|
||||
continue;
|
||||
@@ -249,7 +249,7 @@ public sealed partial class MeleeWeaponSystem
|
||||
targetPos += entRotation.RotateVec(arcComponent.Offset);
|
||||
}
|
||||
|
||||
TransformSystem.SetWorldPosition(xform, targetPos);
|
||||
TransformSystem.SetWorldPosition(uid, targetPos);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1207,11 +1207,12 @@ public abstract partial class InteractionTest
|
||||
BoundKeyFunction key,
|
||||
BoundKeyState state,
|
||||
NetCoordinates? coordinates = null,
|
||||
NetEntity? cursorEntity = null)
|
||||
NetEntity? cursorEntity = null,
|
||||
ScreenCoordinates? screenCoordinates = null)
|
||||
{
|
||||
var coords = coordinates ?? TargetCoords;
|
||||
var target = cursorEntity ?? Target ?? default;
|
||||
ScreenCoordinates screen = default;
|
||||
var screen = screenCoordinates ?? default;
|
||||
|
||||
var funcId = InputManager.NetworkBindMap.KeyFunctionID(key);
|
||||
var message = new ClientFullInputCmdMessage(CTiming.CurTick, CTiming.TickFraction, funcId)
|
||||
|
||||
46
Content.IntegrationTests/Tests/Strip/StrippableTest.cs
Normal file
46
Content.IntegrationTests/Tests/Strip/StrippableTest.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using Content.Client.Interaction;
|
||||
using Content.IntegrationTests.Tests.Interaction;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.Map;
|
||||
|
||||
namespace Content.IntegrationTests.Tests.Strip;
|
||||
|
||||
public sealed class StrippableTest : InteractionTest
|
||||
{
|
||||
protected override string PlayerPrototype => "MobHuman";
|
||||
|
||||
[Test]
|
||||
public async Task DragDropOpensStrip()
|
||||
{
|
||||
// Spawn one tile away
|
||||
TargetCoords = SEntMan.GetNetCoordinates(new EntityCoordinates(MapData.MapUid, 1, 0));
|
||||
await SpawnTarget("MobHuman");
|
||||
|
||||
var userInterface = Comp<UserInterfaceComponent>(Target);
|
||||
Assert.That(userInterface.Actors.Count == 0);
|
||||
|
||||
// screenCoordinates diff needs to be larger than DragDropSystem._deadzone
|
||||
var screenX = CEntMan.System<DragDropSystem>().Deadzone + 1f;
|
||||
|
||||
// Start drag
|
||||
await SetKey(EngineKeyFunctions.Use,
|
||||
BoundKeyState.Down,
|
||||
TargetCoords,
|
||||
Target,
|
||||
screenCoordinates: new ScreenCoordinates(screenX, 0f, WindowId.Main));
|
||||
|
||||
await RunTicks(5);
|
||||
|
||||
// End drag
|
||||
await SetKey(EngineKeyFunctions.Use,
|
||||
BoundKeyState.Up,
|
||||
PlayerCoords,
|
||||
Player,
|
||||
screenCoordinates: new ScreenCoordinates(0f, 0f, WindowId.Main));
|
||||
|
||||
await RunTicks(5);
|
||||
|
||||
Assert.That(userInterface.Actors.Count > 0);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Server.Popups;
|
||||
using Content.Shared.Abilities.Mime;
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.Actions.Events;
|
||||
using Content.Shared.Alert;
|
||||
@@ -29,6 +30,9 @@ namespace Content.Server.Abilities.Mime
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<MimePowersComponent, ComponentInit>(OnComponentInit);
|
||||
SubscribeLocalEvent<MimePowersComponent, InvisibleWallActionEvent>(OnInvisibleWall);
|
||||
|
||||
SubscribeLocalEvent<MimePowersComponent, BreakVowAlertEvent>(OnBreakVowAlert);
|
||||
SubscribeLocalEvent<MimePowersComponent, RetakeVowAlertEvent>(OnRetakeVowAlert);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
@@ -99,6 +103,22 @@ namespace Content.Server.Abilities.Mime
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnBreakVowAlert(Entity<MimePowersComponent> ent, ref BreakVowAlertEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
BreakVow(ent, ent);
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnRetakeVowAlert(Entity<MimePowersComponent> ent, ref RetakeVowAlertEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
RetakeVow(ent, ent);
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Break this mime's vow to not speak.
|
||||
/// </summary>
|
||||
|
||||
@@ -16,6 +16,7 @@ public sealed partial class AdminLogManager
|
||||
|
||||
// TODO ADMIN LOGS make this thread safe or remove thread safety from the main partial class
|
||||
private readonly Dictionary<int, List<SharedAdminLog>> _roundsLogCache = new(MaxRoundsCached);
|
||||
private readonly Queue<int> _roundsLogCacheQueue = new();
|
||||
|
||||
private static readonly Gauge CacheRoundCount = Metrics.CreateGauge(
|
||||
"admin_logs_cache_round_count",
|
||||
@@ -28,19 +29,21 @@ public sealed partial class AdminLogManager
|
||||
// TODO ADMIN LOGS cache previous {MaxRoundsCached} rounds on startup
|
||||
public void CacheNewRound()
|
||||
{
|
||||
List<SharedAdminLog> list;
|
||||
var oldestRound = _currentRoundId - MaxRoundsCached;
|
||||
List<SharedAdminLog>? list = null;
|
||||
|
||||
if (_roundsLogCache.Remove(oldestRound, out var oldestList))
|
||||
_roundsLogCacheQueue.Enqueue(_currentRoundId);
|
||||
if (_roundsLogCacheQueue.Count > MaxRoundsCached)
|
||||
{
|
||||
list = oldestList;
|
||||
list.Clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
list = new List<SharedAdminLog>(LogListInitialSize);
|
||||
var oldestRound = _roundsLogCacheQueue.Dequeue();
|
||||
if (_roundsLogCache.Remove(oldestRound, out var oldestList))
|
||||
{
|
||||
list = oldestList;
|
||||
list.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
list ??= new List<SharedAdminLog>(LogListInitialSize);
|
||||
|
||||
_roundsLogCache.Add(_currentRoundId, list);
|
||||
CacheRoundCount.Set(_roundsLogCache.Count);
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
using Content.Shared.Alert;
|
||||
using Content.Server.Abilities.Mime;
|
||||
|
||||
namespace Content.Server.Alert.Click
|
||||
{
|
||||
///<summary>
|
||||
/// Break your mime vows
|
||||
///</summary>
|
||||
[DataDefinition]
|
||||
public sealed partial class BreakVow : IAlertClick
|
||||
{
|
||||
public void AlertClicked(EntityUid player)
|
||||
{
|
||||
var entManager = IoCManager.Resolve<IEntityManager>();
|
||||
|
||||
if (entManager.TryGetComponent(player, out MimePowersComponent? mimePowers))
|
||||
{
|
||||
entManager.System<MimePowersSystem>().BreakVow(player, mimePowers);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
using Content.Server.Cuffs;
|
||||
using Content.Shared.Alert;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Content.Server.Alert.Click
|
||||
{
|
||||
/// <summary>
|
||||
/// Try to remove handcuffs from yourself
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
[DataDefinition]
|
||||
public sealed partial class RemoveCuffs : IAlertClick
|
||||
{
|
||||
public void AlertClicked(EntityUid player)
|
||||
{
|
||||
var entityManager = IoCManager.Resolve<IEntityManager>();
|
||||
var cuffableSys = entityManager.System<CuffableSystem>();
|
||||
cuffableSys.TryUncuff(player, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
using Content.Server.Ensnaring;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.Ensnaring.Components;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Content.Server.Alert.Click;
|
||||
[UsedImplicitly]
|
||||
[DataDefinition]
|
||||
public sealed partial class RemoveEnsnare : IAlertClick
|
||||
{
|
||||
public void AlertClicked(EntityUid player)
|
||||
{
|
||||
var entManager = IoCManager.Resolve<IEntityManager>();
|
||||
if (entManager.TryGetComponent(player, out EnsnareableComponent? ensnareableComponent))
|
||||
{
|
||||
foreach (var ensnare in ensnareableComponent.Container.ContainedEntities)
|
||||
{
|
||||
if (!entManager.TryGetComponent(ensnare, out EnsnaringComponent? ensnaringComponent))
|
||||
return;
|
||||
|
||||
entManager.EntitySysManager.GetEntitySystem<EnsnareableSystem>().TryFree(player, player, ensnare, ensnaringComponent);
|
||||
|
||||
// Only one snare at a time.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Shared.Alert;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Content.Server.Alert.Click
|
||||
{
|
||||
/// <summary>
|
||||
/// Resist fire
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
[DataDefinition]
|
||||
public sealed partial class ResistFire : IAlertClick
|
||||
{
|
||||
public void AlertClicked(EntityUid player)
|
||||
{
|
||||
var entManager = IoCManager.Resolve<IEntityManager>();
|
||||
|
||||
if (entManager.TryGetComponent(player, out FlammableComponent? flammable))
|
||||
{
|
||||
entManager.System<FlammableSystem>().Resist(player, flammable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
using Content.Shared.Alert;
|
||||
using Content.Server.Abilities.Mime;
|
||||
|
||||
namespace Content.Server.Alert.Click
|
||||
{
|
||||
///<summary>
|
||||
/// Retake your mime vows
|
||||
///</summary>
|
||||
[DataDefinition]
|
||||
public sealed partial class RetakeVow : IAlertClick
|
||||
{
|
||||
public void AlertClicked(EntityUid player)
|
||||
{
|
||||
var entManager = IoCManager.Resolve<IEntityManager>();
|
||||
|
||||
if (entManager.TryGetComponent(player, out MimePowersComponent? mimePowers))
|
||||
{
|
||||
entManager.System<MimePowersSystem>().RetakeVow(player, mimePowers);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.Movement.Pulling.Components;
|
||||
using Content.Shared.Movement.Pulling.Systems;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Content.Server.Alert.Click
|
||||
{
|
||||
/// <summary>
|
||||
/// Stop pulling something
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
[DataDefinition]
|
||||
public sealed partial class StopBeingPulled : IAlertClick
|
||||
{
|
||||
public void AlertClicked(EntityUid player)
|
||||
{
|
||||
var entityManager = IoCManager.Resolve<IEntityManager>();
|
||||
|
||||
if (!entityManager.System<ActionBlockerSystem>().CanInteract(player, null))
|
||||
return;
|
||||
|
||||
if (entityManager.TryGetComponent(player, out PullableComponent? playerPullable))
|
||||
{
|
||||
entityManager.System<PullingSystem>().TryStopPull(player, playerPullable, user: player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
using Content.Server.Shuttles.Systems;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.Shuttles.Components;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Content.Server.Alert.Click
|
||||
{
|
||||
/// <summary>
|
||||
/// Stop piloting shuttle
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
[DataDefinition]
|
||||
public sealed partial class StopPiloting : IAlertClick
|
||||
{
|
||||
public void AlertClicked(EntityUid player)
|
||||
{
|
||||
var entManager = IoCManager.Resolve<IEntityManager>();
|
||||
|
||||
if (entManager.TryGetComponent(player, out PilotComponent? pilotComponent)
|
||||
&& pilotComponent.Console != null)
|
||||
{
|
||||
entManager.System<ShuttleConsoleSystem>().RemovePilot(player, pilotComponent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.Movement.Pulling.Components;
|
||||
using Content.Shared.Movement.Pulling.Systems;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Content.Server.Alert.Click
|
||||
{
|
||||
/// <summary>
|
||||
/// Stop pulling something
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
[DataDefinition]
|
||||
public sealed partial class StopPulling : IAlertClick
|
||||
{
|
||||
public void AlertClicked(EntityUid player)
|
||||
{
|
||||
var entManager = IoCManager.Resolve<IEntityManager>();
|
||||
var ps = entManager.System<PullingSystem>();
|
||||
|
||||
if (entManager.TryGetComponent(player, out PullerComponent? puller) &&
|
||||
entManager.TryGetComponent(puller.Pulling, out PullableComponent? pullableComp))
|
||||
{
|
||||
ps.TryStopPull(puller.Pulling.Value, pullableComp, user: player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
using Content.Server.Body.Systems;
|
||||
using Content.Shared.Alert;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Content.Server.Alert.Click;
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to toggle the internals for a particular entity
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
[DataDefinition]
|
||||
public sealed partial class ToggleInternals : IAlertClick
|
||||
{
|
||||
public void AlertClicked(EntityUid player)
|
||||
{
|
||||
var internalsSystem = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<InternalsSystem>();
|
||||
internalsSystem.ToggleInternals(player, player, false);
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.Buckle;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Content.Server.Alert.Click
|
||||
{
|
||||
/// <summary>
|
||||
/// Unbuckles if player is currently buckled.
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
[DataDefinition]
|
||||
public sealed partial class Unbuckle : IAlertClick
|
||||
{
|
||||
public void AlertClicked(EntityUid player)
|
||||
{
|
||||
IoCManager.Resolve<IEntityManager>().System<SharedBuckleSystem>().TryUnbuckle(player, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,11 +13,15 @@ using Content.Server.Roles.Jobs;
|
||||
using Content.Server.Shuttles.Components;
|
||||
using Content.Server.Station.Systems;
|
||||
using Content.Shared.Antag;
|
||||
using Content.Shared.Clothing;
|
||||
using Content.Shared.GameTicking;
|
||||
using Content.Shared.GameTicking.Components;
|
||||
using Content.Shared.Ghost;
|
||||
using Content.Shared.Humanoid;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Players;
|
||||
using Content.Shared.Preferences.Loadouts;
|
||||
using Content.Shared.Roles;
|
||||
using Content.Shared.Whitelist;
|
||||
using Robust.Server.Audio;
|
||||
using Robust.Server.GameObjects;
|
||||
@@ -25,6 +29,7 @@ using Robust.Server.Player;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
@@ -35,10 +40,13 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelection
|
||||
[Dependency] private readonly IChatManager _chat = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IServerPreferencesManager _pref = default!;
|
||||
[Dependency] private readonly ActorSystem _actors = default!;
|
||||
[Dependency] private readonly AudioSystem _audio = default!;
|
||||
[Dependency] private readonly GhostRoleSystem _ghostRole = default!;
|
||||
[Dependency] private readonly JobSystem _jobs = default!;
|
||||
[Dependency] private readonly LoadoutSystem _loadout = default!;
|
||||
[Dependency] private readonly MindSystem _mind = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
[Dependency] private readonly RoleSystem _role = default!;
|
||||
[Dependency] private readonly StationSpawningSystem _stationSpawning = default!;
|
||||
[Dependency] private readonly TransformSystem _transform = default!;
|
||||
@@ -224,7 +232,7 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelection
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var session = (ICommonSession?) null;
|
||||
var session = (ICommonSession?)null;
|
||||
if (picking)
|
||||
{
|
||||
if (!playerPool.TryPickAndTake(RobustRandom, out session) && noSpawner)
|
||||
@@ -324,17 +332,29 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelection
|
||||
|
||||
// The following is where we apply components, equipment, and other changes to our antagonist entity.
|
||||
EntityManager.AddComponents(player, def.Components);
|
||||
_stationSpawning.EquipStartingGear(player, def.StartingGear);
|
||||
|
||||
// Equip the entity's RoleLoadout and LoadoutGroup
|
||||
List<ProtoId<StartingGearPrototype>>? gear = new();
|
||||
if (def.StartingGear is not null)
|
||||
gear.Add(def.StartingGear.Value);
|
||||
|
||||
_loadout.Equip(player, gear, def.RoleLoadout);
|
||||
|
||||
if (session != null)
|
||||
{
|
||||
var curMind = _mind.CreateMind(session.UserId, Name(antagEnt.Value));
|
||||
_mind.SetUserId(curMind, session.UserId);
|
||||
|
||||
_mind.TransferTo(curMind, antagEnt, ghostCheckOverride: true);
|
||||
_role.MindAddRoles(curMind, def.MindComponents, null, true);
|
||||
ent.Comp.SelectedMinds.Add((curMind, Name(player)));
|
||||
var curMind = session.GetMind();
|
||||
|
||||
if (curMind == null ||
|
||||
!TryComp<MindComponent>(curMind.Value, out var mindComp) ||
|
||||
mindComp.OwnedEntity != antagEnt)
|
||||
{
|
||||
curMind = _mind.CreateMind(session.UserId, Name(antagEnt.Value));
|
||||
_mind.SetUserId(curMind.Value, session.UserId);
|
||||
}
|
||||
|
||||
_mind.TransferTo(curMind.Value, antagEnt, ghostCheckOverride: true);
|
||||
_role.MindAddRoles(curMind.Value, def.MindComponents, null, true);
|
||||
ent.Comp.SelectedMinds.Add((curMind.Value, Name(player)));
|
||||
SendBriefing(session, def.Briefing);
|
||||
}
|
||||
|
||||
@@ -447,7 +467,7 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelection
|
||||
|
||||
private void OnObjectivesTextGetInfo(Entity<AntagSelectionComponent> ent, ref ObjectivesTextGetInfoEvent args)
|
||||
{
|
||||
if (ent.Comp.AgentName is not {} name)
|
||||
if (ent.Comp.AgentName is not { } name)
|
||||
return;
|
||||
|
||||
args.Minds = ent.Comp.SelectedMinds;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Content.Server.Administration.Systems;
|
||||
using Content.Shared.Antag;
|
||||
using Content.Shared.Destructible.Thresholds;
|
||||
using Content.Shared.Preferences.Loadouts;
|
||||
using Content.Shared.Roles;
|
||||
using Content.Shared.Storage;
|
||||
using Content.Shared.Whitelist;
|
||||
@@ -154,6 +155,12 @@ public partial struct AntagSelectionDefinition()
|
||||
[DataField]
|
||||
public ProtoId<StartingGearPrototype>? StartingGear;
|
||||
|
||||
/// <summary>
|
||||
/// A list of role loadouts, from which a randomly selected one will be equipped.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public List<ProtoId<RoleLoadoutPrototype>>? RoleLoadout;
|
||||
|
||||
/// <summary>
|
||||
/// A briefing shown to the player.
|
||||
/// </summary>
|
||||
|
||||
@@ -237,7 +237,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
// TODO: Technically these directions won't be correct but uhh I'm just here for optimisations buddy not to fix my old bugs.
|
||||
if (throwTarget != EntityCoordinates.Invalid)
|
||||
{
|
||||
var pos = ((throwTarget.ToMap(EntityManager, _transformSystem).Position - xform.WorldPosition).Normalized() + dirVec).Normalized();
|
||||
var pos = ((_transformSystem.ToMapCoordinates(throwTarget).Position - _transformSystem.GetWorldPosition(xform)).Normalized() + dirVec).Normalized();
|
||||
_physics.ApplyLinearImpulse(uid, pos * moveForce, body: physics);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -73,6 +73,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
SubscribeLocalEvent<FlammableComponent, IsHotEvent>(OnIsHot);
|
||||
SubscribeLocalEvent<FlammableComponent, TileFireEvent>(OnTileFire);
|
||||
SubscribeLocalEvent<FlammableComponent, RejuvenateEvent>(OnRejuvenate);
|
||||
SubscribeLocalEvent<FlammableComponent, ResistFireAlertEvent>(OnResistFireAlert);
|
||||
|
||||
SubscribeLocalEvent<IgniteOnCollideComponent, StartCollideEvent>(IgniteOnCollide);
|
||||
SubscribeLocalEvent<IgniteOnCollideComponent, LandEvent>(OnIgniteLand);
|
||||
@@ -251,6 +252,15 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
Extinguish(uid, component);
|
||||
}
|
||||
|
||||
private void OnResistFireAlert(Entity<FlammableComponent> ent, ref ResistFireAlertEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
Resist(ent, ent);
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
public void UpdateAppearance(EntityUid uid, FlammableComponent? flammable = null, AppearanceComponent? appearance = null)
|
||||
{
|
||||
if (!Resolve(uid, ref flammable, ref appearance))
|
||||
|
||||
90
Content.Server/Atmos/EntitySystems/GasMinerSystem.cs
Normal file
90
Content.Server/Atmos/EntitySystems/GasMinerSystem.cs
Normal file
@@ -0,0 +1,90 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Content.Server.Atmos.Piping.Components;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Atmos.Components;
|
||||
using Content.Shared.Atmos.EntitySystems;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Server.GameObjects;
|
||||
|
||||
namespace Content.Server.Atmos.EntitySystems;
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed class GasMinerSystem : SharedGasMinerSystem
|
||||
{
|
||||
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
|
||||
[Dependency] private readonly TransformSystem _transformSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<GasMinerComponent, AtmosDeviceUpdateEvent>(OnMinerUpdated);
|
||||
}
|
||||
|
||||
private void OnMinerUpdated(Entity<GasMinerComponent> ent, ref AtmosDeviceUpdateEvent args)
|
||||
{
|
||||
var miner = ent.Comp;
|
||||
var oldState = miner.MinerState;
|
||||
float toSpawn;
|
||||
|
||||
if (!GetValidEnvironment(ent, out var environment) || !Transform(ent).Anchored)
|
||||
{
|
||||
miner.MinerState = GasMinerState.Disabled;
|
||||
}
|
||||
// SpawnAmount is declared in mol/s so to get the amount of gas we hope to mine, we have to multiply this by
|
||||
// how long we have been waiting to spawn it and further cap the number according to the miner's state.
|
||||
else if ((toSpawn = CapSpawnAmount(ent, miner.SpawnAmount * args.dt, environment)) == 0)
|
||||
{
|
||||
miner.MinerState = GasMinerState.Idle;
|
||||
}
|
||||
else
|
||||
{
|
||||
miner.MinerState = GasMinerState.Working;
|
||||
|
||||
// Time to mine some gas.
|
||||
var merger = new GasMixture(1) { Temperature = miner.SpawnTemperature };
|
||||
merger.SetMoles(miner.SpawnGas, toSpawn);
|
||||
_atmosphereSystem.Merge(environment, merger);
|
||||
}
|
||||
|
||||
if (miner.MinerState != oldState)
|
||||
{
|
||||
Dirty(ent);
|
||||
}
|
||||
}
|
||||
|
||||
private bool GetValidEnvironment(Entity<GasMinerComponent> ent, [NotNullWhen(true)] out GasMixture? environment)
|
||||
{
|
||||
var (uid, miner) = ent;
|
||||
var transform = Transform(uid);
|
||||
var position = _transformSystem.GetGridOrMapTilePosition(uid, transform);
|
||||
|
||||
// Treat space as an invalid environment
|
||||
if (_atmosphereSystem.IsTileSpace(transform.GridUid, transform.MapUid, position))
|
||||
{
|
||||
environment = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
environment = _atmosphereSystem.GetContainingMixture((uid, transform), true, true);
|
||||
return environment != null;
|
||||
}
|
||||
|
||||
private float CapSpawnAmount(Entity<GasMinerComponent> ent, float toSpawnTarget, GasMixture environment)
|
||||
{
|
||||
var (uid, miner) = ent;
|
||||
|
||||
// How many moles could we theoretically spawn. Cap by pressure and amount.
|
||||
var allowableMoles = Math.Min(
|
||||
(miner.MaxExternalPressure - environment.Pressure) * environment.Volume / (miner.SpawnTemperature * Atmospherics.R),
|
||||
miner.MaxExternalAmount - environment.TotalMoles);
|
||||
|
||||
var toSpawnReal = Math.Clamp(allowableMoles, 0f, toSpawnTarget);
|
||||
|
||||
if (toSpawnReal < Atmospherics.GasMinMoles) {
|
||||
return 0f;
|
||||
}
|
||||
|
||||
return toSpawnReal;
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
using Content.Shared.Atmos;
|
||||
|
||||
namespace Content.Server.Atmos.Piping.Other.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
public sealed partial class GasMinerComponent : Component
|
||||
{
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool Enabled { get; set; } = true;
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public bool Idle { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// If the number of moles in the external environment exceeds this number, no gas will be mined.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("maxExternalAmount")]
|
||||
public float MaxExternalAmount { get; set; } = float.PositiveInfinity;
|
||||
|
||||
/// <summary>
|
||||
/// If the pressure (in kPA) of the external environment exceeds this number, no gas will be mined.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("maxExternalPressure")]
|
||||
public float MaxExternalPressure { get; set; } = Atmospherics.GasMinerDefaultMaxExternalPressure;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("spawnGas")]
|
||||
public Gas? SpawnGas { get; set; } = null;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("spawnTemperature")]
|
||||
public float SpawnTemperature { get; set; } = Atmospherics.T20C;
|
||||
|
||||
/// <summary>
|
||||
/// Number of moles created per second when the miner is working.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("spawnAmount")]
|
||||
public float SpawnAmount { get; set; } = Atmospherics.MolesCellStandard * 20f;
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Atmos.Piping.Components;
|
||||
using Content.Server.Atmos.Piping.Other.Components;
|
||||
using Content.Shared.Atmos;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Server.GameObjects;
|
||||
|
||||
namespace Content.Server.Atmos.Piping.Other.EntitySystems
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public sealed class GasMinerSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
|
||||
[Dependency] private readonly TransformSystem _transformSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<GasMinerComponent, AtmosDeviceUpdateEvent>(OnMinerUpdated);
|
||||
}
|
||||
|
||||
private void OnMinerUpdated(Entity<GasMinerComponent> ent, ref AtmosDeviceUpdateEvent args)
|
||||
{
|
||||
var miner = ent.Comp;
|
||||
|
||||
if (!GetValidEnvironment(ent, out var environment))
|
||||
{
|
||||
miner.Idle = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// SpawnAmount is declared in mol/s so to get the amount of gas we hope to mine, we have to multiply this by
|
||||
// how long we have been waiting to spawn it and further cap the number according to the miner's state.
|
||||
var toSpawn = CapSpawnAmount(ent, miner.SpawnAmount * args.dt, environment);
|
||||
miner.Idle = toSpawn == 0;
|
||||
if (miner.Idle || !miner.Enabled || !miner.SpawnGas.HasValue)
|
||||
return;
|
||||
|
||||
// Time to mine some gas.
|
||||
|
||||
var merger = new GasMixture(1) { Temperature = miner.SpawnTemperature };
|
||||
merger.SetMoles(miner.SpawnGas.Value, toSpawn);
|
||||
|
||||
_atmosphereSystem.Merge(environment, merger);
|
||||
}
|
||||
|
||||
private bool GetValidEnvironment(Entity<GasMinerComponent> ent, [NotNullWhen(true)] out GasMixture? environment)
|
||||
{
|
||||
var (uid, miner) = ent;
|
||||
var transform = Transform(uid);
|
||||
var position = _transformSystem.GetGridOrMapTilePosition(uid, transform);
|
||||
|
||||
// Treat space as an invalid environment
|
||||
if (_atmosphereSystem.IsTileSpace(transform.GridUid, transform.MapUid, position))
|
||||
{
|
||||
environment = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
environment = _atmosphereSystem.GetContainingMixture((uid, transform), true, true);
|
||||
return environment != null;
|
||||
}
|
||||
|
||||
private float CapSpawnAmount(Entity<GasMinerComponent> ent, float toSpawnTarget, GasMixture environment)
|
||||
{
|
||||
var (uid, miner) = ent;
|
||||
|
||||
// How many moles could we theoretically spawn. Cap by pressure and amount.
|
||||
var allowableMoles = Math.Min(
|
||||
(miner.MaxExternalPressure - environment.Pressure) * environment.Volume / (miner.SpawnTemperature * Atmospherics.R),
|
||||
miner.MaxExternalAmount - environment.TotalMoles);
|
||||
|
||||
var toSpawnReal = Math.Clamp(allowableMoles, 0f, toSpawnTarget);
|
||||
|
||||
if (toSpawnReal < Atmospherics.GasMinMoles) {
|
||||
return 0f;
|
||||
}
|
||||
|
||||
return toSpawnReal;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,4 +25,5 @@ namespace Content.Server.Body.Components
|
||||
[DataField]
|
||||
public ProtoId<AlertPrototype> InternalsAlert = "Internals";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ public sealed class InternalsSystem : EntitySystem
|
||||
SubscribeLocalEvent<InternalsComponent, ComponentShutdown>(OnInternalsShutdown);
|
||||
SubscribeLocalEvent<InternalsComponent, GetVerbsEvent<InteractionVerb>>(OnGetInteractionVerbs);
|
||||
SubscribeLocalEvent<InternalsComponent, InternalsDoAfterEvent>(OnDoAfter);
|
||||
SubscribeLocalEvent<InternalsComponent, ToggleInternalsAlertEvent>(OnToggleInternalsAlert);
|
||||
|
||||
SubscribeLocalEvent<InternalsComponent, StartingGearEquippedEvent>(OnStartingGear);
|
||||
}
|
||||
@@ -161,6 +162,14 @@ public sealed class InternalsSystem : EntitySystem
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnToggleInternalsAlert(Entity<InternalsComponent> ent, ref ToggleInternalsAlertEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
ToggleInternals(ent, ent, false, internals: ent.Comp);
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnInternalsStartup(Entity<InternalsComponent> ent, ref ComponentStartup args)
|
||||
{
|
||||
_alerts.ShowAlert(ent, ent.Comp.InternalsAlert, GetSeverity(ent));
|
||||
|
||||
@@ -28,6 +28,7 @@ namespace Content.Server.Chemistry.EntitySystems
|
||||
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
|
||||
[Dependency] private readonly ThrowingSystem _throwing = default!;
|
||||
[Dependency] private readonly ReactiveSystem _reactive = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
|
||||
|
||||
private const float ReactTime = 0.125f;
|
||||
|
||||
@@ -69,7 +70,7 @@ namespace Content.Server.Chemistry.EntitySystems
|
||||
|
||||
_throwing.TryThrow(vapor, dir, speed, user: user);
|
||||
|
||||
var distance = (target.Position - vaporXform.WorldPosition).Length();
|
||||
var distance = (target.Position - _transformSystem.GetWorldPosition(vaporXform)).Length();
|
||||
var time = (distance / physics.LinearVelocity.Length());
|
||||
despawn.Lifetime = MathF.Min(aliveTime, time);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Console;
|
||||
@@ -55,13 +55,15 @@ namespace Content.Server.Commands
|
||||
{
|
||||
var entMan = IoCManager.Resolve<IEntityManager>();
|
||||
var transform = entMan.GetComponent<TransformComponent>(ent);
|
||||
var transformSystem = entMan.System<SharedTransformSystem>();
|
||||
var worldPosition = transformSystem.GetWorldPosition(transform);
|
||||
|
||||
// gross, is there a better way to do this?
|
||||
ruleString = ruleString.Replace("$ID", ent.ToString());
|
||||
ruleString = ruleString.Replace("$WX",
|
||||
transform.WorldPosition.X.ToString(CultureInfo.InvariantCulture));
|
||||
worldPosition.X.ToString(CultureInfo.InvariantCulture));
|
||||
ruleString = ruleString.Replace("$WY",
|
||||
transform.WorldPosition.Y.ToString(CultureInfo.InvariantCulture));
|
||||
worldPosition.Y.ToString(CultureInfo.InvariantCulture));
|
||||
ruleString = ruleString.Replace("$LX",
|
||||
transform.LocalPosition.X.ToString(CultureInfo.InvariantCulture));
|
||||
ruleString = ruleString.Replace("$LY",
|
||||
@@ -73,12 +75,13 @@ namespace Content.Server.Commands
|
||||
if (player.AttachedEntity is {Valid: true} p)
|
||||
{
|
||||
var pTransform = entMan.GetComponent<TransformComponent>(p);
|
||||
var pWorldPosition = transformSystem.GetWorldPosition(pTransform);
|
||||
|
||||
ruleString = ruleString.Replace("$PID", ent.ToString());
|
||||
ruleString = ruleString.Replace("$PWX",
|
||||
pTransform.WorldPosition.X.ToString(CultureInfo.InvariantCulture));
|
||||
pWorldPosition.X.ToString(CultureInfo.InvariantCulture));
|
||||
ruleString = ruleString.Replace("$PWY",
|
||||
pTransform.WorldPosition.Y.ToString(CultureInfo.InvariantCulture));
|
||||
pWorldPosition.Y.ToString(CultureInfo.InvariantCulture));
|
||||
ruleString = ruleString.Replace("$PLX",
|
||||
pTransform.LocalPosition.X.ToString(CultureInfo.InvariantCulture));
|
||||
ruleString = ruleString.Replace("$PLY",
|
||||
|
||||
@@ -6,6 +6,8 @@ namespace Content.Server.DeviceNetwork.Systems
|
||||
[UsedImplicitly]
|
||||
public sealed class WirelessNetworkSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -25,7 +27,7 @@ namespace Content.Server.DeviceNetwork.Systems
|
||||
return;
|
||||
|
||||
if (xform.MapID != args.SenderTransform.MapID
|
||||
|| (ownPosition - xform.WorldPosition).Length() > sendingComponent.Range)
|
||||
|| (ownPosition - _transformSystem.GetWorldPosition(xform)).Length() > sendingComponent.Range)
|
||||
{
|
||||
args.Cancel();
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ public sealed partial class DragonSystem : EntitySystem
|
||||
}
|
||||
|
||||
// cant put a rift on solars
|
||||
foreach (var tile in grid.GetTilesIntersecting(new Circle(xform.WorldPosition, RiftTileRadius), false))
|
||||
foreach (var tile in grid.GetTilesIntersecting(new Circle(_transform.GetWorldPosition(xform), RiftTileRadius), false))
|
||||
{
|
||||
if (!tile.IsSpace(_tileDef))
|
||||
continue;
|
||||
|
||||
@@ -28,6 +28,7 @@ public sealed partial class EnsnareableSystem
|
||||
SubscribeLocalEvent<EnsnaringComponent, StepTriggeredOffEvent>(OnStepTrigger);
|
||||
SubscribeLocalEvent<EnsnaringComponent, ThrowDoHitEvent>(OnThrowHit);
|
||||
SubscribeLocalEvent<EnsnaringComponent, AttemptPacifiedThrowEvent>(OnAttemptPacifiedThrow);
|
||||
SubscribeLocalEvent<EnsnareableComponent, RemoveEnsnareAlertEvent>(OnRemoveEnsnareAlert);
|
||||
}
|
||||
|
||||
private void OnAttemptPacifiedThrow(Entity<EnsnaringComponent> ent, ref AttemptPacifiedThrowEvent args)
|
||||
@@ -35,6 +36,24 @@ public sealed partial class EnsnareableSystem
|
||||
args.Cancel("pacified-cannot-throw-snare");
|
||||
}
|
||||
|
||||
private void OnRemoveEnsnareAlert(Entity<EnsnareableComponent> ent, ref RemoveEnsnareAlertEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
foreach (var ensnare in ent.Comp.Container.ContainedEntities)
|
||||
{
|
||||
if (!TryComp<EnsnaringComponent>(ensnare, out var ensnaringComponent))
|
||||
return;
|
||||
|
||||
TryFree(ent, ent, ensnare, ensnaringComponent);
|
||||
|
||||
args.Handled = true;
|
||||
// Only one snare at a time.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnComponentRemove(EntityUid uid, EnsnaringComponent component, ComponentRemove args)
|
||||
{
|
||||
if (!TryComp<EnsnareableComponent>(component.Ensnared, out var ensnared))
|
||||
|
||||
@@ -105,7 +105,7 @@ public sealed partial class ExplosionSystem : SharedExplosionSystem
|
||||
|
||||
var xforms = EntityManager.GetEntityQuery<TransformComponent>();
|
||||
var xform = xforms.GetComponent(gridToTransform);
|
||||
var (_, gridWorldRotation, gridWorldMatrix, invGridWorldMatrid) = xform.GetWorldPositionRotationMatrixWithInv(xforms);
|
||||
var (_, gridWorldRotation, gridWorldMatrix, invGridWorldMatrid) = _transformSystem.GetWorldPositionRotationMatrixWithInv(xform, xforms);
|
||||
|
||||
var localEpicentre = (Vector2i) Vector2.Transform(epicentre.Position, invGridWorldMatrid);
|
||||
var matrix = offsetMatrix * gridWorldMatrix * targetMatrix;
|
||||
|
||||
@@ -406,7 +406,7 @@ public sealed partial class ExplosionSystem : SharedExplosionSystem
|
||||
if (player.AttachedEntity is not EntityUid uid)
|
||||
continue;
|
||||
|
||||
var playerPos = Transform(player.AttachedEntity!.Value).WorldPosition;
|
||||
var playerPos = _transformSystem.GetWorldPosition(player.AttachedEntity!.Value);
|
||||
var delta = epicenter.Position - playerPos;
|
||||
|
||||
if (delta.EqualsApprox(Vector2.Zero))
|
||||
|
||||
@@ -30,13 +30,12 @@ public sealed class TwoStageTriggerSystem : EntitySystem
|
||||
{
|
||||
foreach (var (name, entry) in component.SecondStageComponents)
|
||||
{
|
||||
var comp = (Component) _factory.GetComponent(name);
|
||||
var temp = (object) comp;
|
||||
var comp = (Component)_factory.GetComponent(name);
|
||||
var temp = (object)comp;
|
||||
|
||||
if (EntityManager.TryGetComponent(uid, entry.Component.GetType(), out var c))
|
||||
RemComp(uid, c);
|
||||
|
||||
comp.Owner = uid;
|
||||
_serializationManager.CopyTo(entry.Component, ref temp);
|
||||
EntityManager.AddComponent(uid, comp);
|
||||
}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
using Content.Server.GameTicking.Rules;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
|
||||
|
||||
namespace Content.Server.GameTicking.Rules.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Gamerule for simple antagonists that have fixed objectives.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(GenericAntagRuleSystem))]
|
||||
public sealed partial class GenericAntagRuleComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// All antag minds that are using this rule.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public List<EntityUid> Minds = new();
|
||||
|
||||
/// <summary>
|
||||
/// Locale id for the name of the antag used by the roundend summary.
|
||||
/// </summary>
|
||||
[DataField(required: true), ViewVariables(VVAccess.ReadWrite)]
|
||||
public string AgentName = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// List of objective entity prototypes to add to the antag when a mind is added.
|
||||
/// </summary>
|
||||
[DataField(required: true)]
|
||||
public List<EntProtoId> Objectives = new();
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
using Content.Server.GameTicking.Rules.Components;
|
||||
using Content.Server.Objectives;
|
||||
using Content.Shared.Mind;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
|
||||
namespace Content.Server.GameTicking.Rules;
|
||||
|
||||
/// <summary>
|
||||
/// Handles round end text for simple antags.
|
||||
/// Adding objectives is handled in its own system.
|
||||
/// </summary>
|
||||
public sealed class GenericAntagRuleSystem : GameRuleSystem<GenericAntagRuleComponent>
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<GenericAntagRuleComponent, ObjectivesTextGetInfoEvent>(OnObjectivesTextGetInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start a simple antag's game rule.
|
||||
/// If it is invalid the rule is deleted and null is returned.
|
||||
/// </summary>
|
||||
public bool StartRule(string rule, EntityUid mindId, [NotNullWhen(true)] out EntityUid? ruleId, [NotNullWhen(true)] out GenericAntagRuleComponent? comp)
|
||||
{
|
||||
ruleId = GameTicker.AddGameRule(rule);
|
||||
if (!TryComp<GenericAntagRuleComponent>(ruleId, out comp))
|
||||
{
|
||||
Log.Error($"Simple antag rule prototype {rule} is invalid, deleting it.");
|
||||
Del(ruleId);
|
||||
ruleId = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!GameTicker.StartGameRule(ruleId.Value))
|
||||
{
|
||||
Log.Error($"Simple antag rule prototype {rule} failed to start, deleting it.");
|
||||
Del(ruleId);
|
||||
ruleId = null;
|
||||
comp = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
comp.Minds.Add(mindId);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void OnObjectivesTextGetInfo(EntityUid uid, GenericAntagRuleComponent comp, ref ObjectivesTextGetInfoEvent args)
|
||||
{
|
||||
// just temporary until this is deleted
|
||||
args.Minds = comp.Minds.Select(mindId => (mindId, Comp<MindComponent>(mindId).CharacterName ?? "?")).ToList();
|
||||
args.AgentName = Loc.GetString(comp.AgentName);
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
using Content.Server.GameTicking.Rules.Components;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
|
||||
namespace Content.Server.GenericAntag;
|
||||
|
||||
/// <summary>
|
||||
/// Added to a mob to make it a generic antagonist where all its objectives are fixed.
|
||||
/// This is unlike say traitor where it gets objectives picked randomly using difficulty.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A GenericAntag is not necessarily an antagonist, that depends on the roles you do or do not add after.
|
||||
/// </remarks>
|
||||
[RegisterComponent, Access(typeof(GenericAntagSystem))]
|
||||
public sealed partial class GenericAntagComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Gamerule to start when a mind is added.
|
||||
/// This must have <see cref="GenericAntagRuleComponent"/> or it will not work.
|
||||
/// </summary>
|
||||
[DataField(required: true), ViewVariables(VVAccess.ReadWrite)]
|
||||
public EntProtoId Rule = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The rule that's been spawned.
|
||||
/// Used to prevent spawning multiple rules.
|
||||
/// </summary>
|
||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||
public EntityUid? RuleEntity;
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
using Content.Server.GameTicking.Rules;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Mind.Components;
|
||||
|
||||
namespace Content.Server.GenericAntag;
|
||||
|
||||
/// <summary>
|
||||
/// Handles adding objectives to <see cref="GenericAntagComponent"/>s.
|
||||
/// Roundend summary is handled by <see cref="GenericAntagRuleSystem"/>.
|
||||
/// </summary>
|
||||
public sealed class GenericAntagSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedMindSystem _mind = default!;
|
||||
[Dependency] private readonly GenericAntagRuleSystem _genericAntagRule = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<GenericAntagComponent, MindAddedMessage>(OnMindAdded);
|
||||
}
|
||||
|
||||
private void OnMindAdded(EntityUid uid, GenericAntagComponent comp, MindAddedMessage args)
|
||||
{
|
||||
if (!TryComp<MindContainerComponent>(uid, out var mindContainer) || mindContainer.Mind == null)
|
||||
return;
|
||||
|
||||
var mindId = mindContainer.Mind.Value;
|
||||
MakeAntag(uid, mindId, comp);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Turns a player into this antagonist.
|
||||
/// Does the same thing that having a mind added does, use for antag ctrl.
|
||||
/// </summary>
|
||||
public void MakeAntag(EntityUid uid, EntityUid mindId, GenericAntagComponent? comp = null, MindComponent? mind = null)
|
||||
{
|
||||
if (!Resolve(uid, ref comp) || !Resolve(mindId, ref mind))
|
||||
return;
|
||||
|
||||
// only add the rule once
|
||||
if (comp.RuleEntity != null)
|
||||
return;
|
||||
|
||||
// start the rule
|
||||
if (!_genericAntagRule.StartRule(comp.Rule, mindId, out comp.RuleEntity, out var rule))
|
||||
return;
|
||||
|
||||
// let other systems know the antag was created so they can add briefing, roles, etc.
|
||||
// its important that this is before objectives are added since they may depend on roles added here
|
||||
var ev = new GenericAntagCreatedEvent(mindId, mind);
|
||||
RaiseLocalEvent(uid, ref ev);
|
||||
|
||||
// add the objectives from the rule
|
||||
foreach (var id in rule.Objectives)
|
||||
{
|
||||
_mind.TryAddObjective(mindId, mind, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event raised on a player's entity after its simple antag rule is started.
|
||||
/// Use this to add a briefing, roles, etc.
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public record struct GenericAntagCreatedEvent(EntityUid MindId, MindComponent Mind);
|
||||
@@ -201,7 +201,7 @@ namespace Content.Server.Hands.Systems
|
||||
throwEnt = splitStack.Value;
|
||||
}
|
||||
|
||||
var direction = coordinates.ToMapPos(EntityManager, _transformSystem) - Transform(player).WorldPosition;
|
||||
var direction = _transformSystem.ToMapCoordinates(coordinates).Position - _transformSystem.GetWorldPosition(player);
|
||||
if (direction == Vector2.Zero)
|
||||
return true;
|
||||
|
||||
|
||||
@@ -50,8 +50,7 @@ public sealed class RandomHumanoidSystem : EntitySystem
|
||||
{
|
||||
foreach (var entry in prototype.Components.Values)
|
||||
{
|
||||
var comp = (Component) _serialization.CreateCopy(entry.Component, notNullableOverride: true);
|
||||
comp.Owner = humanoid; // This .owner must survive for now.
|
||||
var comp = (Component)_serialization.CreateCopy(entry.Component, notNullableOverride: true);
|
||||
EntityManager.RemoveComponent(humanoid, comp.GetType());
|
||||
EntityManager.AddComponent(humanoid, comp);
|
||||
}
|
||||
|
||||
@@ -23,12 +23,11 @@ namespace Content.Server.Jobs
|
||||
foreach (var (name, data) in Components)
|
||||
{
|
||||
var component = (Component) factory.GetComponent(name);
|
||||
component.Owner = mob;
|
||||
|
||||
var temp = (object) component;
|
||||
var temp = (object)component;
|
||||
serializationManager.CopyTo(data.Component, ref temp);
|
||||
entityManager.RemoveComponent(mob, temp!.GetType());
|
||||
entityManager.AddComponent(mob, (Component) temp);
|
||||
entityManager.AddComponent(mob, (Component)temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ public sealed class GridDraggingSystem : SharedGridDraggingSystem
|
||||
{
|
||||
[Dependency] private readonly IConGroupController _admin = default!;
|
||||
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
|
||||
|
||||
private readonly HashSet<ICommonSession> _draggers = new();
|
||||
|
||||
@@ -76,8 +77,6 @@ public sealed class GridDraggingSystem : SharedGridDraggingSystem
|
||||
return;
|
||||
}
|
||||
|
||||
var gridXform = Transform(grid);
|
||||
|
||||
gridXform.WorldPosition = msg.WorldPosition;
|
||||
_transformSystem.SetWorldPosition(grid, msg.WorldPosition);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Linq;
|
||||
using System.Linq;
|
||||
using Content.Server.Interaction;
|
||||
using Content.Server.Mech.Equipment.Components;
|
||||
using Content.Server.Mech.Systems;
|
||||
@@ -85,7 +85,7 @@ public sealed class MechGrabberSystem : EntitySystem
|
||||
var (mechPos, mechRot) = _transform.GetWorldPositionRotation(mechxform);
|
||||
|
||||
var offset = mechPos + mechRot.RotateVec(component.DepositOffset);
|
||||
_transform.SetWorldPositionRotation(xform, offset, Angle.Zero);
|
||||
_transform.SetWorldPositionRotation(toRemove, offset, Angle.Zero);
|
||||
_mech.UpdateUserInterface(mech);
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ public sealed class StressTestMovementSystem : EntitySystem
|
||||
var x = MathF.Sin(stressTest.Progress * MathHelper.TwoPi);
|
||||
var y = MathF.Cos(stressTest.Progress * MathHelper.TwoPi);
|
||||
|
||||
_transform.SetWorldPosition(transform, stressTest.Origin + new Vector2(x, y) * 5);
|
||||
_transform.SetWorldPosition((uid, transform), stressTest.Origin + new Vector2(x, y) * 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace Content.Server.Pointing.EntitySystems
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly ExplosionSystem _explosion = default!;
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
|
||||
|
||||
private EntityUid? RandomNearbyPlayer(EntityUid uid, RoguePointingArrowComponent? component = null, TransformComponent? transform = null)
|
||||
{
|
||||
@@ -66,27 +67,28 @@ namespace Content.Server.Pointing.EntitySystems
|
||||
}
|
||||
|
||||
component.TurningDelay -= frameTime;
|
||||
var (transformPos, transformRot) = _transformSystem.GetWorldPositionRotation(transform);
|
||||
|
||||
if (component.TurningDelay > 0)
|
||||
{
|
||||
var difference = Comp<TransformComponent>(chasing).WorldPosition - transform.WorldPosition;
|
||||
var difference = _transformSystem.GetWorldPosition(chasing) - transformPos;
|
||||
var angle = difference.ToAngle();
|
||||
var adjusted = angle.Degrees + 90;
|
||||
var newAngle = Angle.FromDegrees(adjusted);
|
||||
|
||||
transform.WorldRotation = newAngle;
|
||||
_transformSystem.SetWorldRotation(transform, newAngle);
|
||||
|
||||
UpdateAppearance(uid, component, transform);
|
||||
continue;
|
||||
}
|
||||
|
||||
transform.WorldRotation += Angle.FromDegrees(20);
|
||||
_transformSystem.SetWorldRotation(transform, transformRot + Angle.FromDegrees(20));
|
||||
|
||||
UpdateAppearance(uid, component, transform);
|
||||
|
||||
var toChased = Comp<TransformComponent>(chasing).WorldPosition - transform.WorldPosition;
|
||||
var toChased = _transformSystem.GetWorldPosition(chasing) - transformPos;
|
||||
|
||||
transform.WorldPosition += toChased * frameTime * component.ChasingSpeed;
|
||||
_transformSystem.SetWorldPosition((uid, transform), transformPos + (toChased * frameTime * component.ChasingSpeed));
|
||||
|
||||
component.ChasingTime -= frameTime;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Content.Server.Administration.Logs;
|
||||
using Content.Server.Administration.Logs;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Chat.Managers;
|
||||
using Content.Server.GameTicking;
|
||||
@@ -157,7 +157,7 @@ public sealed class SpecialRespawnSystem : SharedSpecialRespawnSystem
|
||||
var tile = tileRef.GridIndices;
|
||||
|
||||
var found = false;
|
||||
var (gridPos, _, gridMatrix) = xform.GetWorldPositionRotationMatrix();
|
||||
var (gridPos, _, gridMatrix) = _transform.GetWorldPositionRotationMatrix(xform);
|
||||
var gridBounds = gridMatrix.TransformBox(grid.LocalAABB);
|
||||
|
||||
//Obviously don't put anything ridiculous in here
|
||||
|
||||
@@ -42,6 +42,7 @@ public sealed partial class RevenantSystem
|
||||
[Dependency] private readonly GhostSystem _ghost = default!;
|
||||
[Dependency] private readonly TileSystem _tile = default!;
|
||||
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
|
||||
|
||||
private void InitializeAbilities()
|
||||
{
|
||||
@@ -227,7 +228,7 @@ public sealed partial class RevenantSystem
|
||||
var xform = Transform(uid);
|
||||
if (!TryComp<MapGridComponent>(xform.GridUid, out var map))
|
||||
return;
|
||||
var tiles = map.GetTilesIntersecting(Box2.CenteredAround(xform.WorldPosition,
|
||||
var tiles = map.GetTilesIntersecting(Box2.CenteredAround(_transformSystem.GetWorldPosition(xform),
|
||||
new Vector2(component.DefileRadius * 2, component.DefileRadius))).ToArray();
|
||||
|
||||
_random.Shuffle(tiles);
|
||||
|
||||
@@ -71,6 +71,7 @@ public sealed partial class ShuttleConsoleSystem : SharedShuttleConsoleSystem
|
||||
SubscribeLocalEvent<UndockEvent>(OnUndock);
|
||||
|
||||
SubscribeLocalEvent<PilotComponent, ComponentGetState>(OnGetState);
|
||||
SubscribeLocalEvent<PilotComponent, StopPilotingAlertEvent>(OnStopPilotingAlert);
|
||||
|
||||
SubscribeLocalEvent<FTLDestinationComponent, ComponentStartup>(OnFtlDestStartup);
|
||||
SubscribeLocalEvent<FTLDestinationComponent, ComponentShutdown>(OnFtlDestShutdown);
|
||||
@@ -196,6 +197,14 @@ public sealed partial class ShuttleConsoleSystem : SharedShuttleConsoleSystem
|
||||
args.State = new PilotComponentState(GetNetEntity(component.Console));
|
||||
}
|
||||
|
||||
private void OnStopPilotingAlert(Entity<PilotComponent> ent, ref StopPilotingAlertEvent args)
|
||||
{
|
||||
if (ent.Comp.Console != null)
|
||||
{
|
||||
RemovePilot(ent, ent);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the position and angle of all dockingcomponents.
|
||||
/// </summary>
|
||||
|
||||
@@ -22,6 +22,7 @@ public sealed class ContainmentFieldGeneratorSystem : EntitySystem
|
||||
[Dependency] private readonly PhysicsSystem _physics = default!;
|
||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||
[Dependency] private readonly SharedPointLightSystem _light = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
|
||||
[Dependency] private readonly TagSystem _tags = default!;
|
||||
|
||||
public override void Initialize()
|
||||
@@ -116,7 +117,7 @@ public sealed class ContainmentFieldGeneratorSystem : EntitySystem
|
||||
private void OnUnanchorAttempt(EntityUid uid, ContainmentFieldGeneratorComponent component,
|
||||
UnanchorAttemptEvent args)
|
||||
{
|
||||
if (component.Enabled)
|
||||
if (component.Enabled || component.IsConnected)
|
||||
{
|
||||
_popupSystem.PopupEntity(Loc.GetString("comp-containment-anchor-warning"), args.User, args.User, PopupType.LargeCaution);
|
||||
args.Cancel();
|
||||
@@ -234,7 +235,7 @@ public sealed class ContainmentFieldGeneratorSystem : EntitySystem
|
||||
if (!gen1XForm.Anchored)
|
||||
return false;
|
||||
|
||||
var genWorldPosRot = gen1XForm.GetWorldPositionRotation();
|
||||
var genWorldPosRot = _transformSystem.GetWorldPositionRotation(gen1XForm);
|
||||
var dirRad = dir.ToAngle() + genWorldPosRot.WorldRotation; //needs to be like this for the raycast to work properly
|
||||
|
||||
var ray = new CollisionRay(genWorldPosRot.WorldPosition, dirRad.ToVec(), component.CollisionMask);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Content.Server.Popups;
|
||||
using Content.Server.Popups;
|
||||
using Content.Server.Shuttles.Components;
|
||||
using Content.Server.Singularity.Events;
|
||||
using Content.Shared.Popups;
|
||||
@@ -13,6 +13,7 @@ public sealed class ContainmentFieldSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly ThrowingSystem _throwing = default!;
|
||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -34,8 +35,8 @@ public sealed class ContainmentFieldSystem : EntitySystem
|
||||
|
||||
if (TryComp<PhysicsComponent>(otherBody, out var physics) && physics.Mass <= component.MaxMass && physics.Hard)
|
||||
{
|
||||
var fieldDir = Transform(uid).WorldPosition;
|
||||
var playerDir = Transform(otherBody).WorldPosition;
|
||||
var fieldDir = _transformSystem.GetWorldPosition(uid);
|
||||
var playerDir = _transformSystem.GetWorldPosition(otherBody);
|
||||
|
||||
_throwing.TryThrow(otherBody, playerDir-fieldDir, baseThrowSpeed: component.ThrowForce);
|
||||
}
|
||||
|
||||
@@ -137,13 +137,22 @@ public sealed class RadiationCollectorSystem : EntitySystem
|
||||
|
||||
private void OnExamined(EntityUid uid, RadiationCollectorComponent component, ExaminedEvent args)
|
||||
{
|
||||
if (!TryGetLoadedGasTank(uid, out var gasTank))
|
||||
using (args.PushGroup(nameof(RadiationCollectorComponent)))
|
||||
{
|
||||
args.PushMarkup(Loc.GetString("power-radiation-collector-gas-tank-missing"));
|
||||
return;
|
||||
}
|
||||
args.PushMarkup(Loc.GetString("power-radiation-collector-enabled", ("state", component.Enabled)));
|
||||
|
||||
args.PushMarkup(Loc.GetString("power-radiation-collector-gas-tank-present"));
|
||||
if (!TryGetLoadedGasTank(uid, out var gasTank))
|
||||
{
|
||||
args.PushMarkup(Loc.GetString("power-radiation-collector-gas-tank-missing"));
|
||||
}
|
||||
else
|
||||
{
|
||||
_appearance.TryGetData<int>(uid, RadiationCollectorVisuals.PressureState, out var state);
|
||||
|
||||
args.PushMarkup(Loc.GetString("power-radiation-collector-gas-tank-present",
|
||||
("fullness", state)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAnalyzed(EntityUid uid, RadiationCollectorComponent component, GasAnalyzerScanEvent args)
|
||||
|
||||
@@ -18,6 +18,7 @@ namespace Content.Server.Solar.EntitySystems
|
||||
{
|
||||
[Dependency] private readonly IRobustRandom _robustRandom = default!;
|
||||
[Dependency] private readonly SharedPhysicsSystem _physicsSystem = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum panel angular velocity range - used to stop people rotating panels fast enough that the lag prevention becomes noticable
|
||||
@@ -112,7 +113,7 @@ namespace Content.Server.Solar.EntitySystems
|
||||
while (query.MoveNext(out var uid, out var panel, out var xform))
|
||||
{
|
||||
TotalPanelPower += panel.MaxSupply * panel.Coverage;
|
||||
xform.WorldRotation = TargetPanelRotation;
|
||||
_transformSystem.SetWorldRotation(xform, TargetPanelRotation);
|
||||
_updateQueue.Enqueue((uid, panel));
|
||||
}
|
||||
}
|
||||
@@ -135,7 +136,7 @@ namespace Content.Server.Solar.EntitySystems
|
||||
// directly downwards (abs(theta) = pi) = coverage -1
|
||||
// as TowardsSun + = CCW,
|
||||
// panelRelativeToSun should - = CW
|
||||
var panelRelativeToSun = xform.WorldRotation - TowardsSun;
|
||||
var panelRelativeToSun = _transformSystem.GetWorldRotation(xform) - TowardsSun;
|
||||
// essentially, given cos = X & sin = Y & Y is 'downwards',
|
||||
// then for the first 90 degrees of rotation in either direction,
|
||||
// this plots the lower-right quadrant of a circle.
|
||||
@@ -153,7 +154,7 @@ namespace Content.Server.Solar.EntitySystems
|
||||
if (coverage > 0)
|
||||
{
|
||||
// Determine if the solar panel is occluded, and zero out coverage if so.
|
||||
var ray = new CollisionRay(xform.WorldPosition, TowardsSun.ToWorldVec(), (int) CollisionGroup.Opaque);
|
||||
var ray = new CollisionRay(_transformSystem.GetWorldPosition(xform), TowardsSun.ToWorldVec(), (int) CollisionGroup.Opaque);
|
||||
var rayCastResults = _physicsSystem.IntersectRayWithPredicate(
|
||||
xform.MapID,
|
||||
ray,
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Content.Server.Speech
|
||||
{
|
||||
public sealed class AccentSystem : EntitySystem
|
||||
{
|
||||
public static readonly Regex SentenceRegex = new(@"(?<=[\.!\?])", RegexOptions.Compiled);
|
||||
public static readonly Regex SentenceRegex = new(@"(?<=[\.!\?‽])(?![\.!\?‽])", RegexOptions.Compiled);
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
|
||||
@@ -7,5 +7,4 @@ namespace Content.Server.Speech.Components;
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
[Access(typeof(FrenchAccentSystem))]
|
||||
public sealed partial class FrenchAccentComponent : Component
|
||||
{ }
|
||||
public sealed partial class FrenchAccentComponent : Component {}
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
namespace Content.Server.Speech.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
public sealed partial class SpanishAccentComponent : Component
|
||||
{
|
||||
}
|
||||
}
|
||||
namespace Content.Server.Speech.Components;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class SpanishAccentComponent : Component {}
|
||||
|
||||
@@ -27,10 +27,10 @@ public sealed class FrenchAccentSystem : EntitySystem
|
||||
|
||||
msg = _replacement.ApplyReplacements(msg, "french");
|
||||
|
||||
// replaces th with dz
|
||||
// replaces th with z
|
||||
msg = RegexTh.Replace(msg, "'z");
|
||||
|
||||
// removes the letter h from the start of words.
|
||||
// replaces h with ' at the start of words.
|
||||
msg = RegexStartH.Replace(msg, "'");
|
||||
|
||||
// spaces out ! ? : and ;.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Text;
|
||||
using Content.Server.Speech.Components;
|
||||
|
||||
namespace Content.Server.Speech.EntitySystems
|
||||
@@ -14,7 +15,7 @@ namespace Content.Server.Speech.EntitySystems
|
||||
// Insert E before every S
|
||||
message = InsertS(message);
|
||||
// If a sentence ends with ?, insert a reverse ? at the beginning of the sentence
|
||||
message = ReplaceQuestionMark(message);
|
||||
message = ReplacePunctuation(message);
|
||||
return message;
|
||||
}
|
||||
|
||||
@@ -36,24 +37,32 @@ namespace Content.Server.Speech.EntitySystems
|
||||
return msg;
|
||||
}
|
||||
|
||||
private string ReplaceQuestionMark(string message)
|
||||
private string ReplacePunctuation(string message)
|
||||
{
|
||||
var sentences = AccentSystem.SentenceRegex.Split(message);
|
||||
var msg = "";
|
||||
var msg = new StringBuilder();
|
||||
foreach (var s in sentences)
|
||||
{
|
||||
if (s.EndsWith("?", StringComparison.Ordinal)) // We've got a question => add ¿ to the beginning
|
||||
var toInsert = new StringBuilder();
|
||||
for (var i = s.Length - 1; i >= 0 && "?!‽".Contains(s[i]); i--)
|
||||
{
|
||||
// Because we don't split by whitespace, we may have some spaces in front of the sentence.
|
||||
// So we add the symbol before the first non space char
|
||||
msg += s.Insert(s.Length - s.TrimStart().Length, "¿");
|
||||
toInsert.Append(s[i] switch
|
||||
{
|
||||
'?' => '¿',
|
||||
'!' => '¡',
|
||||
'‽' => '⸘',
|
||||
_ => ' '
|
||||
});
|
||||
}
|
||||
else
|
||||
if (toInsert.Length == 0)
|
||||
{
|
||||
msg += s;
|
||||
msg.Append(s);
|
||||
} else
|
||||
{
|
||||
msg.Append(s.Insert(s.Length - s.TrimStart().Length, toInsert.ToString()));
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
return msg.ToString();
|
||||
}
|
||||
|
||||
private void OnAccent(EntityUid uid, SpanishAccentComponent component, AccentGetEvent args)
|
||||
|
||||
@@ -54,7 +54,6 @@ public sealed partial class BiomePrototype : IPrototype, IInheritingPrototype
|
||||
foreach (var data in ChunkComponents.Values)
|
||||
{
|
||||
var comp = (Component) serialization.CreateCopy(data.Component, notNullableOverride: true);
|
||||
comp.Owner = target; // look im sorry ok this .owner has to live until engine api exists
|
||||
entityManager.AddComponent(target, comp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@ public sealed partial class WorldgenConfigPrototype : IPrototype
|
||||
foreach (var data in Components.Values)
|
||||
{
|
||||
var comp = (Component) serialization.CreateCopy(data.Component, notNullableOverride: true);
|
||||
comp.Owner = target; // look im sorry ok this .owner has to live until engine api exists
|
||||
entityManager.AddComponent(target, comp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Numerics;
|
||||
using System.Numerics;
|
||||
using Content.Server.Worldgen.Components;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace Content.Server.Worldgen.Systems;
|
||||
public abstract class BaseWorldSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly WorldControllerSystem _worldController = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a chunk's coordinates in chunk space as an integer value.
|
||||
@@ -25,7 +26,7 @@ public abstract class BaseWorldSystem : EntitySystem
|
||||
if (!Resolve(ent, ref xform))
|
||||
throw new Exception("Failed to resolve transform, somehow.");
|
||||
|
||||
return WorldGen.WorldToChunkCoords(xform.WorldPosition).Floored();
|
||||
return WorldGen.WorldToChunkCoords(_transformSystem.GetWorldPosition(xform)).Floored();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -40,7 +41,7 @@ public abstract class BaseWorldSystem : EntitySystem
|
||||
if (!Resolve(ent, ref xform))
|
||||
throw new Exception("Failed to resolve transform, somehow.");
|
||||
|
||||
return WorldGen.WorldToChunkCoords(xform.WorldPosition);
|
||||
return WorldGen.WorldToChunkCoords(_transformSystem.GetWorldPosition(xform));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -182,13 +182,12 @@ public sealed partial class ArtifactSystem
|
||||
EntityManager.RemoveComponent(uid, reg.Type);
|
||||
}
|
||||
|
||||
var comp = (Component) _componentFactory.GetComponent(reg);
|
||||
comp.Owner = uid;
|
||||
var comp = (Component)_componentFactory.GetComponent(reg);
|
||||
|
||||
var temp = (object) comp;
|
||||
var temp = (object)comp;
|
||||
_serialization.CopyTo(entry.Component, ref temp);
|
||||
EntityManager.RemoveComponent(uid, temp!.GetType());
|
||||
EntityManager.AddComponent(uid, (Component) temp!);
|
||||
EntityManager.AddComponent(uid, (Component)temp!);
|
||||
}
|
||||
|
||||
node.Discovered = true;
|
||||
@@ -218,12 +217,11 @@ public sealed partial class ArtifactSystem
|
||||
// if the entity prototype contained the component originally
|
||||
if (entityPrototype?.Components.TryGetComponent(name, out var entry) ?? false)
|
||||
{
|
||||
var comp = (Component) _componentFactory.GetComponent(name);
|
||||
comp.Owner = uid;
|
||||
var temp = (object) comp;
|
||||
var comp = (Component)_componentFactory.GetComponent(name);
|
||||
var temp = (object)comp;
|
||||
_serialization.CopyTo(entry, ref temp);
|
||||
EntityManager.RemoveComponent(uid, temp!.GetType());
|
||||
EntityManager.AddComponent(uid, (Component) temp);
|
||||
EntityManager.AddComponent(uid, (Component)temp);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Numerics;
|
||||
using System.Numerics;
|
||||
using Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Components;
|
||||
using Content.Server.Xenoarchaeology.XenoArtifacts.Events;
|
||||
using Content.Shared.Maps;
|
||||
@@ -31,7 +31,7 @@ public sealed class ThrowArtifactSystem : EntitySystem
|
||||
if (TryComp<MapGridComponent>(xform.GridUid, out var grid))
|
||||
{
|
||||
var tiles = grid.GetTilesIntersecting(
|
||||
Box2.CenteredAround(xform.WorldPosition, new Vector2(component.Range * 2, component.Range)));
|
||||
Box2.CenteredAround(_transform.GetWorldPosition(xform), new Vector2(component.Range * 2, component.Range)));
|
||||
|
||||
foreach (var tile in tiles)
|
||||
{
|
||||
|
||||
@@ -110,4 +110,9 @@ public enum LogType
|
||||
/// A player did an item-use interaction of an item they were holding onto another object.
|
||||
/// </summary>
|
||||
InteractUsing = 92,
|
||||
|
||||
/// <summary>
|
||||
/// Storage & entity-storage related interactions
|
||||
/// </summary>
|
||||
Storage = 93,
|
||||
}
|
||||
|
||||
7
Content.Shared/Abilities/Mime/MimePowers.cs
Normal file
7
Content.Shared/Abilities/Mime/MimePowers.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
using Content.Shared.Alert;
|
||||
|
||||
namespace Content.Shared.Abilities.Mime;
|
||||
|
||||
public sealed partial class BreakVowAlertEvent : BaseAlertEvent;
|
||||
|
||||
public sealed partial class RetakeVowAlertEvent : BaseAlertEvent;
|
||||
@@ -76,11 +76,11 @@ public sealed partial class AlertPrototype : IPrototype
|
||||
public bool SupportsSeverity => MaxSeverity != -1;
|
||||
|
||||
/// <summary>
|
||||
/// Defines what to do when the alert is clicked.
|
||||
/// This will always be null on clientside.
|
||||
/// Event raised on the user when they click on this alert.
|
||||
/// Can be null.
|
||||
/// </summary>
|
||||
[DataField(serverOnly: true)]
|
||||
public IAlertClick? OnClick { get; private set; }
|
||||
[DataField]
|
||||
public BaseAlertEvent? ClickEvent;
|
||||
|
||||
/// <param name="severity">severity level, if supported by this alert</param>
|
||||
/// <returns>the icon path to the texture for the provided severity level</returns>
|
||||
@@ -114,3 +114,17 @@ public sealed partial class AlertPrototype : IPrototype
|
||||
return Icons[severity.Value - _minSeverity];
|
||||
}
|
||||
}
|
||||
|
||||
[ImplicitDataDefinitionForInheritors]
|
||||
public abstract partial class BaseAlertEvent : HandledEntityEventArgs
|
||||
{
|
||||
public EntityUid User;
|
||||
|
||||
public ProtoId<AlertPrototype> AlertId;
|
||||
|
||||
protected BaseAlertEvent(EntityUid user, ProtoId<AlertPrototype> alertId)
|
||||
{
|
||||
User = user;
|
||||
AlertId = alertId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,7 +195,7 @@ public abstract class AlertsSystem : EntitySystem
|
||||
|
||||
SubscribeLocalEvent<AlertAutoRemoveComponent, EntityUnpausedEvent>(OnAutoRemoveUnPaused);
|
||||
|
||||
SubscribeNetworkEvent<ClickAlertEvent>(HandleClickAlert);
|
||||
SubscribeAllEvent<ClickAlertEvent>(HandleClickAlert);
|
||||
SubscribeLocalEvent<PrototypesReloadedEventArgs>(HandlePrototypesReloaded);
|
||||
LoadPrototypes();
|
||||
}
|
||||
@@ -328,7 +328,20 @@ public abstract class AlertsSystem : EntitySystem
|
||||
return;
|
||||
}
|
||||
|
||||
alert.OnClick?.AlertClicked(player.Value);
|
||||
ActivateAlert(player.Value, alert);
|
||||
}
|
||||
|
||||
public bool ActivateAlert(EntityUid user, AlertPrototype alert)
|
||||
{
|
||||
if (alert.ClickEvent is not { } clickEvent)
|
||||
return false;
|
||||
|
||||
clickEvent.Handled = false;
|
||||
clickEvent.User = user;
|
||||
clickEvent.AlertId = alert.ID;
|
||||
|
||||
RaiseLocalEvent(user, (object) clickEvent, true);
|
||||
return clickEvent.Handled;
|
||||
}
|
||||
|
||||
private void OnPlayerAttached(EntityUid uid, AlertsComponent component, PlayerAttachedEvent args)
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
namespace Content.Shared.Alert
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines what should happen when an alert is clicked.
|
||||
/// </summary>
|
||||
public interface IAlertClick
|
||||
{
|
||||
/// <summary>
|
||||
/// Invoked on server side when user clicks an alert.
|
||||
/// </summary>
|
||||
/// <param name="player"></param>
|
||||
void AlertClicked(EntityUid player);
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
using Content.Shared.Alert;
|
||||
using Robust.Shared.Audio;
|
||||
|
||||
namespace Content.Shared.Atmos.Components;
|
||||
@@ -27,3 +28,5 @@ public sealed partial class ExtinguishOnInteractComponent : Component
|
||||
[DataField]
|
||||
public LocId ExtinguishFailed = "candle-extinguish-failed";
|
||||
}
|
||||
|
||||
public sealed partial class ResistFireAlertEvent : BaseAlertEvent;
|
||||
|
||||
60
Content.Shared/Atmos/Components/GasMinerComponent.cs
Normal file
60
Content.Shared/Atmos/Components/GasMinerComponent.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Atmos.Components;
|
||||
|
||||
[NetworkedComponent]
|
||||
[AutoGenerateComponentState]
|
||||
[RegisterComponent]
|
||||
public sealed partial class GasMinerComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Operational state of the miner.
|
||||
/// </summary>
|
||||
[AutoNetworkedField]
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public GasMinerState MinerState = GasMinerState.Disabled;
|
||||
|
||||
/// <summary>
|
||||
/// If the number of moles in the external environment exceeds this number, no gas will be mined.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField]
|
||||
public float MaxExternalAmount = float.PositiveInfinity;
|
||||
|
||||
/// <summary>
|
||||
/// If the pressure (in kPA) of the external environment exceeds this number, no gas will be mined.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField]
|
||||
public float MaxExternalPressure = Atmospherics.GasMinerDefaultMaxExternalPressure;
|
||||
|
||||
/// <summary>
|
||||
/// Gas to spawn.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField(required: true)]
|
||||
public Gas SpawnGas;
|
||||
|
||||
/// <summary>
|
||||
/// Temperature in Kelvin.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField]
|
||||
public float SpawnTemperature = Atmospherics.T20C;
|
||||
|
||||
/// <summary>
|
||||
/// Number of moles created per second when the miner is working.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField]
|
||||
public float SpawnAmount = Atmospherics.MolesCellStandard * 20f;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum GasMinerState : byte
|
||||
{
|
||||
Disabled,
|
||||
Idle,
|
||||
Working,
|
||||
}
|
||||
55
Content.Shared/Atmos/EntitySystems/SharedGasMinerSystem.cs
Normal file
55
Content.Shared/Atmos/EntitySystems/SharedGasMinerSystem.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using Content.Shared.Atmos.Components;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Temperature;
|
||||
|
||||
namespace Content.Shared.Atmos.EntitySystems;
|
||||
|
||||
public abstract class SharedGasMinerSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedAtmosphereSystem _sharedAtmosphereSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<GasMinerComponent, ExaminedEvent>(OnExamine);
|
||||
}
|
||||
|
||||
private void OnExamine(Entity<GasMinerComponent> ent, ref ExaminedEvent args)
|
||||
{
|
||||
var component = ent.Comp;
|
||||
|
||||
using (args.PushGroup(nameof(GasMinerComponent)))
|
||||
{
|
||||
args.PushMarkup(Loc.GetString("gas-miner-mines-text",
|
||||
("gas", Loc.GetString(_sharedAtmosphereSystem.GetGas(component.SpawnGas).Name))));
|
||||
|
||||
args.PushText(Loc.GetString("gas-miner-amount-text",
|
||||
("moles", $"{component.SpawnAmount:0.#}")));
|
||||
|
||||
args.PushText(Loc.GetString("gas-miner-temperature-text",
|
||||
("tempK", $"{component.SpawnTemperature:0.#}"),
|
||||
("tempC", $"{TemperatureHelpers.KelvinToCelsius(component.SpawnTemperature):0.#}")));
|
||||
|
||||
if (component.MaxExternalAmount < float.PositiveInfinity)
|
||||
{
|
||||
args.PushText(Loc.GetString("gas-miner-moles-cutoff-text",
|
||||
("moles", $"{component.MaxExternalAmount:0.#}")));
|
||||
}
|
||||
|
||||
if (component.MaxExternalPressure < float.PositiveInfinity)
|
||||
{
|
||||
args.PushText(Loc.GetString("gas-miner-pressure-cutoff-text",
|
||||
("pressure", $"{component.MaxExternalPressure:0.#}")));
|
||||
}
|
||||
|
||||
args.AddMarkup(component.MinerState switch
|
||||
{
|
||||
GasMinerState.Disabled => Loc.GetString("gas-miner-state-disabled-text"),
|
||||
GasMinerState.Idle => Loc.GetString("gas-miner-state-idle-text"),
|
||||
GasMinerState.Working => Loc.GetString("gas-miner-state-working-text"),
|
||||
// C# pattern matching is not exhaustive for enums
|
||||
_ => throw new IndexOutOfRangeException(nameof(component.MinerState)),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Bed.Cryostorage;
|
||||
|
||||
/// <summary>
|
||||
/// Serves as a whitelist that allows an entity with this component to enter cryostorage.
|
||||
/// It will also require MindContainerComponent.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class CanEnterCryostorageComponent : Component { }
|
||||
@@ -89,7 +89,7 @@ public abstract class SharedCryostorageSystem : EntitySystem
|
||||
return;
|
||||
}
|
||||
|
||||
if (!TryComp<MindContainerComponent>(args.EntityUid, out var mindContainer))
|
||||
if (!HasComp<CanEnterCryostorageComponent>(args.EntityUid) || !TryComp<MindContainerComponent>(args.EntityUid, out var mindContainer))
|
||||
{
|
||||
args.Cancel();
|
||||
return;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.Interaction;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization;
|
||||
@@ -79,6 +80,7 @@ public sealed class BuckleState(NetEntity? buckledTo, bool dontCollide, TimeSpan
|
||||
public readonly TimeSpan? BuckleTime = buckleTime;
|
||||
}
|
||||
|
||||
public sealed partial class UnbuckleAlertEvent : BaseAlertEvent;
|
||||
|
||||
/// <summary>
|
||||
/// Event raised directed at a strap entity before some entity gets buckled to it.
|
||||
|
||||
@@ -41,6 +41,7 @@ public abstract partial class SharedBuckleSystem
|
||||
SubscribeLocalEvent<BuckleComponent, StartPullAttemptEvent>(OnPullAttempt);
|
||||
SubscribeLocalEvent<BuckleComponent, BeingPulledAttemptEvent>(OnBeingPulledAttempt);
|
||||
SubscribeLocalEvent<BuckleComponent, PullStartedMessage>(OnPullStarted);
|
||||
SubscribeLocalEvent<BuckleComponent, UnbuckleAlertEvent>(OnUnbuckleAlert);
|
||||
|
||||
SubscribeLocalEvent<BuckleComponent, InsertIntoEntityStorageAttemptEvent>(OnBuckleInsertIntoEntityStorageAttempt);
|
||||
|
||||
@@ -86,6 +87,13 @@ public abstract partial class SharedBuckleSystem
|
||||
Unbuckle(ent!, args.PullerUid);
|
||||
}
|
||||
|
||||
private void OnUnbuckleAlert(Entity<BuckleComponent> ent, ref UnbuckleAlertEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
args.Handled = TryUnbuckle(ent, ent, ent);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Transform
|
||||
|
||||
@@ -29,7 +29,7 @@ public sealed partial class SolutionTransferComponent : Component
|
||||
/// </summary>
|
||||
[DataField("maxTransferAmount")]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public FixedPoint2 MaximumTransferAmount { get; set; } = FixedPoint2.New(50);
|
||||
public FixedPoint2 MaximumTransferAmount { get; set; } = FixedPoint2.New(100);
|
||||
|
||||
/// <summary>
|
||||
/// Can this entity take reagent from reagent tanks?
|
||||
|
||||
@@ -9,10 +9,8 @@ namespace Content.Shared.Clothing.Components;
|
||||
public sealed partial class LoadoutComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// A list of starting gears, of which one will be given.
|
||||
/// A list of starting gears, of which one will be given, before RoleLoadouts are equipped.
|
||||
/// All elements are weighted the same in the list.
|
||||
///
|
||||
/// If not specified, <see cref="RoleLoadout"/> will be used instead.
|
||||
/// </summary>
|
||||
[DataField("prototypes")]
|
||||
[AutoNetworkedField]
|
||||
@@ -21,8 +19,6 @@ public sealed partial class LoadoutComponent : Component
|
||||
/// <summary>
|
||||
/// A list of role loadouts, of which one will be given.
|
||||
/// All elements are weighted the same in the list.
|
||||
///
|
||||
/// If not specified, <see cref="StartingGear"/> will be used instead.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
[AutoNetworkedField]
|
||||
|
||||
@@ -139,22 +139,37 @@ public sealed class LoadoutSystem : EntitySystem
|
||||
|
||||
private void OnMapInit(EntityUid uid, LoadoutComponent component, MapInitEvent args)
|
||||
{
|
||||
// Use starting gear if specified
|
||||
if (component.StartingGear != null)
|
||||
Equip(uid, component.StartingGear, component.RoleLoadout);
|
||||
}
|
||||
|
||||
public void Equip(EntityUid uid, List<ProtoId<StartingGearPrototype>>? startingGear,
|
||||
List<ProtoId<RoleLoadoutPrototype>>? loadoutGroups)
|
||||
{
|
||||
// First, randomly pick a startingGear profile from those specified, and equip it.
|
||||
if (startingGear != null && startingGear.Count > 0)
|
||||
_station.EquipStartingGear(uid, _random.Pick(startingGear));
|
||||
|
||||
if (loadoutGroups == null)
|
||||
{
|
||||
_station.EquipStartingGear(uid, _random.Pick(component.StartingGear));
|
||||
GearEquipped(uid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (component.RoleLoadout == null)
|
||||
return;
|
||||
|
||||
// ...otherwise equip from role loadout
|
||||
var id = _random.Pick(component.RoleLoadout);
|
||||
// Then, randomly pick a RoleLoadout profile from those specified, and process/equip all LoadoutGroups from it.
|
||||
// For non-roundstart mobs there is no SelectedLoadout data, so minValue must be set in each LoadoutGroup to force selection.
|
||||
var id = _random.Pick(loadoutGroups);
|
||||
var proto = _protoMan.Index(id);
|
||||
var loadout = new RoleLoadout(id);
|
||||
loadout.SetDefault(GetProfile(uid), _actors.GetSession(uid), _protoMan, true);
|
||||
_station.EquipRoleLoadout(uid, loadout, proto);
|
||||
|
||||
GearEquipped(uid);
|
||||
}
|
||||
|
||||
public void GearEquipped(EntityUid uid)
|
||||
{
|
||||
var ev = new StartingGearEquippedEvent(uid);
|
||||
RaiseLocalEvent(uid, ref ev);
|
||||
}
|
||||
|
||||
public HumanoidCharacterProfile GetProfile(EntityUid? uid)
|
||||
|
||||
@@ -20,13 +20,13 @@ namespace Content.Shared.Construction.Conditions
|
||||
|
||||
// get blueprint and user position
|
||||
var transformSystem = entManager.System<SharedTransformSystem>();
|
||||
var userWorldPosition = entManager.GetComponent<TransformComponent>(user).WorldPosition;
|
||||
var userWorldPosition = transformSystem.GetWorldPosition(user);
|
||||
var objWorldPosition = location.ToMap(entManager, transformSystem).Position;
|
||||
|
||||
// find direction from user to blueprint
|
||||
var userToObject = (objWorldPosition - userWorldPosition);
|
||||
// get direction of the grid being placed on as an offset.
|
||||
var gridRotation = entManager.GetComponent<TransformComponent>(location.EntityId).WorldRotation;
|
||||
var gridRotation = transformSystem.GetWorldRotation(location.EntityId);
|
||||
var directionWithOffset = gridRotation.RotateVec(direction.ToVec());
|
||||
|
||||
// dot product will be positive if user direction and blueprint are co-directed
|
||||
|
||||
@@ -46,6 +46,8 @@ public sealed partial class CuffableComponent : Component
|
||||
public ProtoId<AlertPrototype> CuffedAlert = "Handcuffed";
|
||||
}
|
||||
|
||||
public sealed partial class RemoveCuffsAlertEvent : BaseAlertEvent;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class CuffableComponentState : ComponentState
|
||||
{
|
||||
|
||||
@@ -66,6 +66,7 @@ namespace Content.Shared.Cuffs
|
||||
SubscribeLocalEvent<CuffableComponent, RejuvenateEvent>(OnRejuvenate);
|
||||
SubscribeLocalEvent<CuffableComponent, ComponentInit>(OnStartup);
|
||||
SubscribeLocalEvent<CuffableComponent, AttemptStopPullingEvent>(HandleStopPull);
|
||||
SubscribeLocalEvent<CuffableComponent, RemoveCuffsAlertEvent>(OnRemoveCuffsAlert);
|
||||
SubscribeLocalEvent<CuffableComponent, UpdateCanMoveEvent>(HandleMoveAttempt);
|
||||
SubscribeLocalEvent<CuffableComponent, IsEquippingAttemptEvent>(OnEquipAttempt);
|
||||
SubscribeLocalEvent<CuffableComponent, IsUnequippingAttemptEvent>(OnUnequipAttempt);
|
||||
@@ -248,6 +249,14 @@ namespace Content.Shared.Cuffs
|
||||
args.Cancelled = true;
|
||||
}
|
||||
|
||||
private void OnRemoveCuffsAlert(Entity<CuffableComponent> ent, ref RemoveCuffsAlertEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
TryUncuff(ent, ent, cuffable: ent.Comp);
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void AddUncuffVerb(EntityUid uid, CuffableComponent component, GetVerbsEvent<Verb> args)
|
||||
{
|
||||
// Can the user access the cuffs, and is there even anything to uncuff?
|
||||
|
||||
@@ -47,6 +47,8 @@ public sealed partial class EnsnareableComponent : Component
|
||||
public ProtoId<AlertPrototype> EnsnaredAlert = "Ensnared";
|
||||
}
|
||||
|
||||
public sealed partial class RemoveEnsnareAlertEvent : BaseAlertEvent;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class EnsnareableComponentState : ComponentState
|
||||
{
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Content.Shared.DragDrop;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Interaction;
|
||||
@@ -14,6 +15,38 @@ public sealed class DeployFoldableSystem : EntitySystem
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<DeployFoldableComponent, AfterInteractEvent>(OnAfterInteract);
|
||||
SubscribeLocalEvent<DeployFoldableComponent, CanDragEvent>(OnCanDrag);
|
||||
SubscribeLocalEvent<DeployFoldableComponent, DragDropDraggedEvent>(OnDragDropDragged);
|
||||
SubscribeLocalEvent<DeployFoldableComponent, CanDropDraggedEvent>(OnCanDropDragged);
|
||||
}
|
||||
|
||||
private void OnCanDropDragged(Entity<DeployFoldableComponent> ent, ref CanDropDraggedEvent args)
|
||||
{
|
||||
if (args.User != args.Target)
|
||||
return;
|
||||
|
||||
args.Handled = true;
|
||||
args.CanDrop = true;
|
||||
}
|
||||
|
||||
private void OnDragDropDragged(Entity<DeployFoldableComponent> ent, ref DragDropDraggedEvent args)
|
||||
{
|
||||
if (!TryComp<FoldableComponent>(ent, out var foldable)
|
||||
|| !_foldable.TrySetFolded(ent, foldable, true))
|
||||
return;
|
||||
|
||||
_hands.PickupOrDrop(args.User, ent.Owner);
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnCanDrag(Entity<DeployFoldableComponent> ent, ref CanDragEvent args)
|
||||
{
|
||||
if (!TryComp<FoldableComponent>(ent, out var foldable)
|
||||
|| foldable.IsFolded)
|
||||
return;
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnAfterInteract(Entity<DeployFoldableComponent> ent, ref AfterInteractEvent args)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.DoAfter;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Internals;
|
||||
@@ -7,3 +8,5 @@ namespace Content.Shared.Internals;
|
||||
public sealed partial class InternalsDoAfterEvent : SimpleDoAfterEvent
|
||||
{
|
||||
}
|
||||
|
||||
public sealed partial class ToggleInternalsAlertEvent : BaseAlertEvent;
|
||||
|
||||
@@ -369,11 +369,10 @@ public abstract class SharedMagicSystem : EntitySystem
|
||||
if (HasComp(ev.Target, data.Component.GetType()))
|
||||
continue;
|
||||
|
||||
var component = (Component) _compFact.GetComponent(name);
|
||||
component.Owner = ev.Target;
|
||||
var temp = (object) component;
|
||||
var component = (Component)_compFact.GetComponent(name);
|
||||
var temp = (object)component;
|
||||
_seriMan.CopyTo(data.Component, ref temp);
|
||||
EntityManager.AddComponent(ev.Target, (Component) temp!);
|
||||
EntityManager.AddComponent(ev.Target, (Component)temp!);
|
||||
}
|
||||
}
|
||||
// End Change Component Spells
|
||||
|
||||
@@ -80,11 +80,6 @@ public partial class MobStateSystem
|
||||
case MobState.Dead:
|
||||
RemComp<CollisionWakeComponent>(target);
|
||||
_standing.Stand(target);
|
||||
if (!_standing.IsDown(target) && TryComp<PhysicsComponent>(target, out var physics))
|
||||
{
|
||||
_physics.SetCanCollide(target, true, body: physics);
|
||||
}
|
||||
|
||||
break;
|
||||
case MobState.Invalid:
|
||||
//unused
|
||||
@@ -115,12 +110,6 @@ public partial class MobStateSystem
|
||||
case MobState.Dead:
|
||||
EnsureComp<CollisionWakeComponent>(target);
|
||||
_standing.Down(target);
|
||||
|
||||
if (_standing.IsDown(target) && TryComp<PhysicsComponent>(target, out var physics))
|
||||
{
|
||||
_physics.SetCanCollide(target, false, body: physics);
|
||||
}
|
||||
|
||||
_appearance.SetData(target, MobStateVisuals.State, MobState.Dead);
|
||||
break;
|
||||
case MobState.Invalid:
|
||||
|
||||
@@ -42,3 +42,5 @@ public sealed partial class PullableComponent : Component
|
||||
[DataField]
|
||||
public ProtoId<AlertPrototype> PulledAlert = "Pulled";
|
||||
}
|
||||
|
||||
public sealed partial class StopBeingPulledAlertEvent : BaseAlertEvent;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user