Merge branch 'space-wizards:master' into elk-new
This commit is contained in:
@@ -103,7 +103,7 @@ public sealed partial class AirAlarmWindow : FancyWindow
|
||||
_temperature.SetMarkup(Loc.GetString("air-alarm-ui-window-temperature", ("tempC", $"{TemperatureHelpers.KelvinToCelsius(state.TemperatureAverage):0.#}"), ("temperature", $"{state.TemperatureAverage:0.##}")));
|
||||
_alarmState.SetMarkup(Loc.GetString("air-alarm-ui-window-alarm-state",
|
||||
("color", ColorForAlarm(state.AlarmType)),
|
||||
("state", $"{state.AlarmType}")));
|
||||
("state", state.AlarmType)));
|
||||
UpdateModeSelector(state.Mode);
|
||||
UpdateAutoMode(state.AutoMode);
|
||||
foreach (var (addr, dev) in state.DeviceData)
|
||||
|
||||
@@ -27,11 +27,11 @@ public sealed partial class SensorInfo : BoxContainer
|
||||
|
||||
_address = address;
|
||||
|
||||
SensorAddress.Title = $"{address} : {data.AlarmState}";
|
||||
SensorAddress.Title = Loc.GetString("air-alarm-ui-window-listing-title", ("address", _address), ("state", data.AlarmState));
|
||||
|
||||
AlarmStateLabel.SetMarkup(Loc.GetString("air-alarm-ui-window-alarm-state-indicator",
|
||||
("color", AirAlarmWindow.ColorForAlarm(data.AlarmState)),
|
||||
("state", $"{data.AlarmState}")));
|
||||
("state", data.AlarmState)));
|
||||
PressureLabel.SetMarkup(Loc.GetString("air-alarm-ui-window-pressure-indicator",
|
||||
("color", AirAlarmWindow.ColorForThreshold(data.Pressure, data.PressureThreshold)),
|
||||
("pressure", $"{data.Pressure:0.##}")));
|
||||
@@ -90,11 +90,11 @@ public sealed partial class SensorInfo : BoxContainer
|
||||
|
||||
public void ChangeData(AtmosSensorData data)
|
||||
{
|
||||
SensorAddress.Title = $"{_address} : {data.AlarmState}";
|
||||
SensorAddress.Title = Loc.GetString("air-alarm-ui-window-listing-title", ("address", _address), ("state", data.AlarmState));
|
||||
|
||||
AlarmStateLabel.SetMarkup(Loc.GetString("air-alarm-ui-window-alarm-state-indicator",
|
||||
("color", AirAlarmWindow.ColorForAlarm(data.AlarmState)),
|
||||
("state", $"{data.AlarmState}")));
|
||||
("state", data.AlarmState)));
|
||||
|
||||
PressureLabel.SetMarkup(Loc.GetString("air-alarm-ui-window-pressure-indicator",
|
||||
("color", AirAlarmWindow.ColorForThreshold(data.Pressure, data.PressureThreshold)),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Content.Client.Rotation;
|
||||
using Content.Shared.Buckle;
|
||||
using Content.Shared.Buckle.Components;
|
||||
using Content.Shared.Movement.Systems;
|
||||
using Content.Shared.Rotation;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
@@ -21,6 +22,15 @@ internal sealed class BuckleSystem : SharedBuckleSystem
|
||||
SubscribeLocalEvent<StrapComponent, MoveEvent>(OnStrapMoveEvent);
|
||||
SubscribeLocalEvent<BuckleComponent, BuckledEvent>(OnBuckledEvent);
|
||||
SubscribeLocalEvent<BuckleComponent, UnbuckledEvent>(OnUnbuckledEvent);
|
||||
SubscribeLocalEvent<BuckleComponent, AttemptMobCollideEvent>(OnMobCollide);
|
||||
}
|
||||
|
||||
private void OnMobCollide(Entity<BuckleComponent> ent, ref AttemptMobCollideEvent args)
|
||||
{
|
||||
if (ent.Comp.Buckled)
|
||||
{
|
||||
args.Cancelled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnStrapMoveEvent(EntityUid uid, StrapComponent component, ref MoveEvent args)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Numerics;
|
||||
using Content.Client.Sprite;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Utility;
|
||||
@@ -17,12 +18,14 @@ public sealed class ClickableSystem : EntitySystem
|
||||
|
||||
private EntityQuery<ClickableComponent> _clickableQuery;
|
||||
private EntityQuery<TransformComponent> _xformQuery;
|
||||
private EntityQuery<FadingSpriteComponent> _fadingSpriteQuery;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
_clickableQuery = GetEntityQuery<ClickableComponent>();
|
||||
_xformQuery = GetEntityQuery<TransformComponent>();
|
||||
_fadingSpriteQuery = GetEntityQuery<FadingSpriteComponent>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -34,7 +37,7 @@ public sealed class ClickableSystem : EntitySystem
|
||||
/// The draw depth for the sprite that captured the click.
|
||||
/// </param>
|
||||
/// <returns>True if the click worked, false otherwise.</returns>
|
||||
public bool CheckClick(Entity<ClickableComponent?, SpriteComponent, TransformComponent?> entity, Vector2 worldPos, IEye eye, out int drawDepth, out uint renderOrder, out float bottom)
|
||||
public bool CheckClick(Entity<ClickableComponent?, SpriteComponent, TransformComponent?, FadingSpriteComponent?> entity, Vector2 worldPos, IEye eye, bool excludeFaded, out int drawDepth, out uint renderOrder, out float bottom)
|
||||
{
|
||||
if (!_clickableQuery.Resolve(entity.Owner, ref entity.Comp1, false))
|
||||
{
|
||||
@@ -52,6 +55,14 @@ public sealed class ClickableSystem : EntitySystem
|
||||
return false;
|
||||
}
|
||||
|
||||
if (excludeFaded && _fadingSpriteQuery.Resolve(entity.Owner, ref entity.Comp4, false))
|
||||
{
|
||||
drawDepth = default;
|
||||
renderOrder = default;
|
||||
bottom = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
var sprite = entity.Comp2;
|
||||
var transform = entity.Comp3;
|
||||
|
||||
|
||||
@@ -113,18 +113,18 @@ namespace Content.Client.Gameplay
|
||||
return first.IsValid() ? first : null;
|
||||
}
|
||||
|
||||
public IEnumerable<EntityUid> GetClickableEntities(EntityCoordinates coordinates)
|
||||
public IEnumerable<EntityUid> GetClickableEntities(EntityCoordinates coordinates, bool excludeFaded = true)
|
||||
{
|
||||
var transformSystem = _entitySystemManager.GetEntitySystem<SharedTransformSystem>();
|
||||
return GetClickableEntities(transformSystem.ToMapCoordinates(coordinates));
|
||||
return GetClickableEntities(transformSystem.ToMapCoordinates(coordinates), excludeFaded);
|
||||
}
|
||||
|
||||
public IEnumerable<EntityUid> GetClickableEntities(MapCoordinates coordinates)
|
||||
public IEnumerable<EntityUid> GetClickableEntities(MapCoordinates coordinates, bool excludeFaded = true)
|
||||
{
|
||||
return GetClickableEntities(coordinates, _eyeManager.CurrentEye);
|
||||
return GetClickableEntities(coordinates, _eyeManager.CurrentEye, excludeFaded);
|
||||
}
|
||||
|
||||
public IEnumerable<EntityUid> GetClickableEntities(MapCoordinates coordinates, IEye? eye)
|
||||
public IEnumerable<EntityUid> GetClickableEntities(MapCoordinates coordinates, IEye? eye, bool excludeFaded = true)
|
||||
{
|
||||
/*
|
||||
* TODO:
|
||||
@@ -147,7 +147,7 @@ namespace Content.Client.Gameplay
|
||||
foreach (var entity in entities)
|
||||
{
|
||||
if (clickQuery.TryGetComponent(entity.Uid, out var component) &&
|
||||
clickables.CheckClick((entity.Uid, component, entity.Component, entity.Transform), coordinates.Position, eye, out var drawDepthClicked, out var renderOrder, out var bottom))
|
||||
clickables.CheckClick((entity.Uid, component, entity.Component, entity.Transform), coordinates.Position, eye, excludeFaded, out var drawDepthClicked, out var renderOrder, out var bottom))
|
||||
{
|
||||
foundEntities.Add((entity.Uid, drawDepthClicked, renderOrder, bottom));
|
||||
}
|
||||
|
||||
42
Content.Client/Movement/Systems/MobCollisionSystem.cs
Normal file
42
Content.Client/Movement/Systems/MobCollisionSystem.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System.Numerics;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Movement.Components;
|
||||
using Content.Shared.Movement.Systems;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.Physics.Components;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Client.Movement.Systems;
|
||||
|
||||
public sealed class MobCollisionSystem : SharedMobCollisionSystem
|
||||
{
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly IPlayerManager _player = default!;
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
if (!CfgManager.GetCVar(CCVars.MovementMobPushing))
|
||||
return;
|
||||
|
||||
if (_timing.IsFirstTimePredicted)
|
||||
{
|
||||
var player = _player.LocalEntity;
|
||||
|
||||
if (MobQuery.TryComp(player, out var comp) && PhysicsQuery.TryComp(player, out var physics))
|
||||
{
|
||||
HandleCollisions((player.Value, comp, physics), frameTime);
|
||||
}
|
||||
}
|
||||
|
||||
base.Update(frameTime);
|
||||
}
|
||||
|
||||
protected override void RaiseCollisionEvent(EntityUid uid, Vector2 direction, float speedMod)
|
||||
{
|
||||
RaisePredictiveEvent(new MobCollisionMessage()
|
||||
{
|
||||
Direction = direction,
|
||||
SpeedModifier = speedMod,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -62,16 +62,16 @@ public sealed class MoverController : SharedMoverController
|
||||
|
||||
private void OnRelayPlayerAttached(Entity<RelayInputMoverComponent> entity, ref LocalPlayerAttachedEvent args)
|
||||
{
|
||||
Physics.UpdateIsPredicted(entity.Owner);
|
||||
Physics.UpdateIsPredicted(entity.Comp.RelayEntity);
|
||||
PhysicsSystem.UpdateIsPredicted(entity.Owner);
|
||||
PhysicsSystem.UpdateIsPredicted(entity.Comp.RelayEntity);
|
||||
if (MoverQuery.TryGetComponent(entity.Comp.RelayEntity, out var inputMover))
|
||||
SetMoveInput((entity.Comp.RelayEntity, inputMover), MoveButtons.None);
|
||||
}
|
||||
|
||||
private void OnRelayPlayerDetached(Entity<RelayInputMoverComponent> entity, ref LocalPlayerDetachedEvent args)
|
||||
{
|
||||
Physics.UpdateIsPredicted(entity.Owner);
|
||||
Physics.UpdateIsPredicted(entity.Comp.RelayEntity);
|
||||
PhysicsSystem.UpdateIsPredicted(entity.Owner);
|
||||
PhysicsSystem.UpdateIsPredicted(entity.Comp.RelayEntity);
|
||||
if (MoverQuery.TryGetComponent(entity.Comp.RelayEntity, out var inputMover))
|
||||
SetMoveInput((entity.Comp.RelayEntity, inputMover), MoveButtons.None);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
using System.Numerics;
|
||||
using Content.Client.Gameplay;
|
||||
using Content.Shared.Sprite;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Input;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.State;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Physics.Systems;
|
||||
using Robust.Shared.Physics;
|
||||
|
||||
namespace Content.Client.Sprite;
|
||||
@@ -17,6 +23,9 @@ public sealed class SpriteFadeSystem : EntitySystem
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IStateManager _stateManager = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly IUserInterfaceManager _uiManager = default!;
|
||||
[Dependency] private readonly IInputManager _inputManager = default!;
|
||||
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
||||
|
||||
private readonly HashSet<FadingSpriteComponent> _comps = new();
|
||||
|
||||
@@ -24,6 +33,11 @@ public sealed class SpriteFadeSystem : EntitySystem
|
||||
private EntityQuery<SpriteFadeComponent> _fadeQuery;
|
||||
private EntityQuery<FadingSpriteComponent> _fadingQuery;
|
||||
|
||||
/// <summary>
|
||||
/// Radius of the mouse point for the intersection test
|
||||
/// </summary>
|
||||
private static Vector2 MouseRadius = new Vector2(10f * float.Epsilon, 10f * float.Epsilon);
|
||||
|
||||
private const float TargetAlpha = 0.4f;
|
||||
private const float ChangeRate = 1f;
|
||||
|
||||
@@ -46,46 +60,82 @@ public sealed class SpriteFadeSystem : EntitySystem
|
||||
sprite.Color = sprite.Color.WithAlpha(component.OriginalAlpha);
|
||||
}
|
||||
|
||||
public override void FrameUpdate(float frameTime)
|
||||
/// <summary>
|
||||
/// Adds sprites to the fade set, and brings their alpha downwards
|
||||
/// </summary>
|
||||
private void FadeIn(float change)
|
||||
{
|
||||
base.FrameUpdate(frameTime);
|
||||
|
||||
var player = _playerManager.LocalEntity;
|
||||
var change = ChangeRate * frameTime;
|
||||
// ExcludeBoundingBox is set if we don't want to fade this sprite within the collision bounding boxes for the given POI
|
||||
var pointsOfInterest = new List<(MapCoordinates Point, bool ExcludeBoundingBox)>();
|
||||
|
||||
if (TryComp(player, out TransformComponent? playerXform) &&
|
||||
_stateManager.CurrentState is GameplayState state &&
|
||||
_spriteQuery.TryGetComponent(player, out var playerSprite))
|
||||
if (_uiManager.CurrentlyHovered is IViewportControl vp
|
||||
&& _inputManager.MouseScreenPosition.IsValid)
|
||||
{
|
||||
var mapPos = _transform.GetMapCoordinates(_playerManager.LocalEntity!.Value, xform: playerXform);
|
||||
pointsOfInterest.Add((vp.PixelToMap(_inputManager.MouseScreenPosition.Position), true));
|
||||
}
|
||||
|
||||
// Also want to handle large entities even if they may not be clickable.
|
||||
foreach (var ent in state.GetClickableEntities(mapPos))
|
||||
if (TryComp(player, out TransformComponent? playerXform))
|
||||
{
|
||||
pointsOfInterest.Add((_transform.GetMapCoordinates(_playerManager.LocalEntity!.Value, xform: playerXform), false));
|
||||
}
|
||||
|
||||
if (_stateManager.CurrentState is GameplayState state && _spriteQuery.TryGetComponent(player, out var playerSprite))
|
||||
{
|
||||
foreach (var (mapPos, excludeBB) in pointsOfInterest)
|
||||
{
|
||||
if (ent == player ||
|
||||
!_fadeQuery.HasComponent(ent) ||
|
||||
!_spriteQuery.TryGetComponent(ent, out var sprite) ||
|
||||
sprite.DrawDepth < playerSprite.DrawDepth)
|
||||
// Also want to handle large entities even if they may not be clickable.
|
||||
foreach (var ent in state.GetClickableEntities(mapPos, excludeFaded: false))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (ent == player ||
|
||||
!_fadeQuery.HasComponent(ent) ||
|
||||
!_spriteQuery.TryGetComponent(ent, out var sprite) ||
|
||||
sprite.DrawDepth < playerSprite.DrawDepth)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!_fadingQuery.TryComp(ent, out var fading))
|
||||
{
|
||||
fading = AddComp<FadingSpriteComponent>(ent);
|
||||
fading.OriginalAlpha = sprite.Color.A;
|
||||
}
|
||||
if (excludeBB)
|
||||
{
|
||||
var test = new Box2Rotated(mapPos.Position - MouseRadius, mapPos.Position + MouseRadius);
|
||||
var collided = false;
|
||||
foreach (var fixture in _physics.GetCollidingEntities(mapPos.MapId, test))
|
||||
{
|
||||
if (fixture.Owner == ent)
|
||||
{
|
||||
collided = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (collided)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_comps.Add(fading);
|
||||
var newColor = Math.Max(sprite.Color.A - change, TargetAlpha);
|
||||
if (!_fadingQuery.TryComp(ent, out var fading))
|
||||
{
|
||||
fading = AddComp<FadingSpriteComponent>(ent);
|
||||
fading.OriginalAlpha = sprite.Color.A;
|
||||
}
|
||||
|
||||
if (!sprite.Color.A.Equals(newColor))
|
||||
{
|
||||
sprite.Color = sprite.Color.WithAlpha(newColor);
|
||||
_comps.Add(fading);
|
||||
var newColor = Math.Max(sprite.Color.A - change, TargetAlpha);
|
||||
|
||||
if (!sprite.Color.A.Equals(newColor))
|
||||
{
|
||||
sprite.Color = sprite.Color.WithAlpha(newColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bring sprites back up to their original alpha if they aren't in the fade set, and removes their fade component when done
|
||||
/// </summary>
|
||||
private void FadeOut(float change)
|
||||
{
|
||||
var query = AllEntityQuery<FadingSpriteComponent>();
|
||||
while (query.MoveNext(out var uid, out var comp))
|
||||
{
|
||||
@@ -106,6 +156,16 @@ public sealed class SpriteFadeSystem : EntitySystem
|
||||
RemCompDeferred<FadingSpriteComponent>(uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void FrameUpdate(float frameTime)
|
||||
{
|
||||
base.FrameUpdate(frameTime);
|
||||
|
||||
var change = ChangeRate * frameTime;
|
||||
|
||||
FadeIn(change);
|
||||
FadeOut(change);
|
||||
|
||||
_comps.Clear();
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ using Robust.Client.State;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.Verbs
|
||||
@@ -36,6 +37,8 @@ namespace Content.Client.Verbs
|
||||
|
||||
private float _lookupSize;
|
||||
|
||||
private static readonly ProtoId<TagPrototype> HideContextMenuTag = "HideContextMenu";
|
||||
|
||||
/// <summary>
|
||||
/// These flags determine what entities the user can see on the context menu.
|
||||
/// </summary>
|
||||
@@ -147,7 +150,7 @@ namespace Content.Client.Verbs
|
||||
|
||||
for (var i = entities.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (_tagSystem.HasTag(entities[i], "HideContextMenu"))
|
||||
if (_tagSystem.HasTag(entities[i], HideContextMenuTag))
|
||||
entities.RemoveSwap(i);
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ public static partial class PoolManager
|
||||
(CVars.NetBufferSize.Name, "0"),
|
||||
(CCVars.InteractionRateLimitCount.Name, "9999999"),
|
||||
(CCVars.InteractionRateLimitPeriod.Name, "0.1"),
|
||||
(CCVars.MovementMobPushing.Name, "false"),
|
||||
};
|
||||
|
||||
public static async Task SetupCVars(RobustIntegrationTest.IntegrationInstance instance, PoolSettings settings)
|
||||
|
||||
@@ -80,7 +80,7 @@ namespace Content.IntegrationTests.Tests
|
||||
|
||||
var pos = clientEntManager.System<SharedTransformSystem>().GetWorldPosition(clientEnt);
|
||||
|
||||
hit = clientEntManager.System<ClickableSystem>().CheckClick((clientEnt, null, sprite, null), new Vector2(clickPosX, clickPosY) + pos, eye, out _, out _, out _);
|
||||
hit = clientEntManager.System<ClickableSystem>().CheckClick((clientEnt, null, sprite, null), new Vector2(clickPosX, clickPosY) + pos, eye, false, out _, out _, out _);
|
||||
});
|
||||
|
||||
await server.WaitPost(() =>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Linq;
|
||||
using System.Linq;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Damage.Prototypes;
|
||||
using Content.Shared.Execution;
|
||||
@@ -52,7 +52,7 @@ public sealed class SuicideCommandTests
|
||||
name: test version of the material reclaimer
|
||||
components:
|
||||
- type: MaterialReclaimer";
|
||||
|
||||
private static readonly ProtoId<TagPrototype> CannotSuicideTag = "CannotSuicide";
|
||||
/// <summary>
|
||||
/// Run the suicide command in the console
|
||||
/// Should successfully kill the player and ghost them
|
||||
@@ -201,7 +201,7 @@ public sealed class SuicideCommandTests
|
||||
mobStateComp = entManager.GetComponent<MobStateComponent>(player);
|
||||
});
|
||||
|
||||
tagSystem.AddTag(player, "CannotSuicide");
|
||||
tagSystem.AddTag(player, CannotSuicideTag);
|
||||
|
||||
// Check that running the suicide command kills the player
|
||||
// and properly ghosts them without them being able to return to their body
|
||||
|
||||
@@ -42,21 +42,9 @@ namespace Content.Server.Access.Systems
|
||||
access.Tags.UnionWith(targetAccess.Tags);
|
||||
var addedLength = access.Tags.Count - beforeLength;
|
||||
|
||||
if (addedLength == 0)
|
||||
{
|
||||
_popupSystem.PopupEntity(Loc.GetString("agent-id-no-new", ("card", args.Target)), args.Target.Value, args.User);
|
||||
return;
|
||||
}
|
||||
|
||||
Dirty(uid, access);
|
||||
|
||||
if (addedLength == 1)
|
||||
{
|
||||
_popupSystem.PopupEntity(Loc.GetString("agent-id-new-1", ("card", args.Target)), args.Target.Value, args.User);
|
||||
return;
|
||||
}
|
||||
|
||||
_popupSystem.PopupEntity(Loc.GetString("agent-id-new", ("number", addedLength), ("card", args.Target)), args.Target.Value, args.User);
|
||||
if (addedLength > 0)
|
||||
Dirty(uid, access);
|
||||
}
|
||||
|
||||
private void AfterUIOpen(EntityUid uid, AgentIDCardComponent component, AfterActivatableUIOpenEvent args)
|
||||
|
||||
@@ -168,7 +168,7 @@ public sealed class IdCardConsoleSystem : SharedIdCardConsoleSystem
|
||||
|
||||
/*TODO: ECS SharedIdCardConsoleComponent and then log on card ejection, together with the save.
|
||||
This current implementation is pretty shit as it logs 27 entries (27 lines) if someone decides to give themselves AA*/
|
||||
_adminLogger.Add(LogType.Action, LogImpact.High,
|
||||
_adminLogger.Add(LogType.Action, LogImpact.Medium,
|
||||
$"{ToPrettyString(player):player} has modified {ToPrettyString(targetId):entity} with the following accesses: [{string.Join(", ", addedTags.Union(removedTags))}] [{string.Join(", ", newAccessList)}]");
|
||||
}
|
||||
|
||||
|
||||
@@ -43,5 +43,13 @@ namespace Content.Server.Administration.Commands
|
||||
|
||||
_entities.System<MindSystem>().ControlMob(player.UserId, target.Value);
|
||||
}
|
||||
|
||||
public CompletionResult GetCompletion(IConsoleShell shell, string[] args)
|
||||
{
|
||||
if (args.Length != 1)
|
||||
return CompletionResult.Empty;
|
||||
|
||||
return CompletionResult.FromOptions(CompletionHelper.NetEntities(args[0], entManager: _entities));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +50,9 @@ public sealed class PlantHolderSystem : EntitySystem
|
||||
public const float HydroponicsSpeedMultiplier = 1f;
|
||||
public const float HydroponicsConsumptionMultiplier = 2f;
|
||||
|
||||
private static readonly ProtoId<TagPrototype> HoeTag = "Hoe";
|
||||
private static readonly ProtoId<TagPrototype> PlantSampleTakerTag = "PlantSampleTaker";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -203,7 +206,7 @@ public sealed class PlantHolderSystem : EntitySystem
|
||||
return;
|
||||
}
|
||||
|
||||
if (_tagSystem.HasTag(args.Used, "Hoe"))
|
||||
if (_tagSystem.HasTag(args.Used, HoeTag))
|
||||
{
|
||||
args.Handled = true;
|
||||
if (component.WeedLevel > 0)
|
||||
@@ -243,7 +246,7 @@ public sealed class PlantHolderSystem : EntitySystem
|
||||
return;
|
||||
}
|
||||
|
||||
if (_tagSystem.HasTag(args.Used, "PlantSampleTaker"))
|
||||
if (_tagSystem.HasTag(args.Used, PlantSampleTakerTag))
|
||||
{
|
||||
args.Handled = true;
|
||||
if (component.Seed == null)
|
||||
|
||||
@@ -4,6 +4,7 @@ using Content.Shared.Chat;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Item;
|
||||
using Content.Shared.Mind;
|
||||
@@ -13,6 +14,7 @@ using Content.Shared.Mobs.Systems;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Tag;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Chat;
|
||||
|
||||
@@ -26,6 +28,8 @@ public sealed class SuicideSystem : EntitySystem
|
||||
[Dependency] private readonly GhostSystem _ghostSystem = default!;
|
||||
[Dependency] private readonly SharedSuicideSystem _suicide = default!;
|
||||
|
||||
private static readonly ProtoId<TagPrototype> CannotSuicideTag = "CannotSuicide";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -59,7 +63,7 @@ public sealed class SuicideSystem : EntitySystem
|
||||
|
||||
// Suicide is considered a fail if the user wasn't able to ghost
|
||||
// Suiciding with the CannotSuicide tag will ghost the player but not kill the body
|
||||
if (!suicideGhostEvent.Handled || _tagSystem.HasTag(victim, "CannotSuicide"))
|
||||
if (!suicideGhostEvent.Handled || _tagSystem.HasTag(victim, CannotSuicideTag))
|
||||
return false;
|
||||
|
||||
var suicideEvent = new SuicideEvent(victim);
|
||||
@@ -94,7 +98,7 @@ public sealed class SuicideSystem : EntitySystem
|
||||
|
||||
// CannotSuicide tag will allow the user to ghost, but also return to their mind
|
||||
// This is kind of weird, not sure what it applies to?
|
||||
if (_tagSystem.HasTag(victim, "CannotSuicide"))
|
||||
if (_tagSystem.HasTag(victim, CannotSuicideTag))
|
||||
args.CanReturnToBody = true;
|
||||
|
||||
if (_ghostSystem.OnGhostAttempt(victim.Comp.Mind.Value, args.CanReturnToBody, mind: mindComponent))
|
||||
@@ -149,7 +153,7 @@ public sealed class SuicideSystem : EntitySystem
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
var othersMessage = Loc.GetString("suicide-command-default-text-others", ("name", victim));
|
||||
var othersMessage = Loc.GetString("suicide-command-default-text-others", ("name", Identity.Entity(victim, EntityManager)));
|
||||
_popup.PopupEntity(othersMessage, victim, Filter.PvsExcept(victim), true);
|
||||
|
||||
var selfMessage = Loc.GetString("suicide-command-default-text-self");
|
||||
|
||||
@@ -9,6 +9,7 @@ using Content.Shared.Projectiles;
|
||||
using Content.Shared.Tag;
|
||||
using Content.Shared.Weapons.Melee.Events;
|
||||
using Robust.Shared.Collections;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Chemistry.EntitySystems;
|
||||
|
||||
@@ -24,6 +25,8 @@ public sealed class SolutionInjectOnCollideSystem : EntitySystem
|
||||
[Dependency] private readonly SharedSolutionContainerSystem _solutionContainer = default!;
|
||||
[Dependency] private readonly TagSystem _tag = default!;
|
||||
|
||||
private static readonly ProtoId<TagPrototype> HardsuitTag = "Hardsuit";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -93,7 +96,7 @@ public sealed class SolutionInjectOnCollideSystem : EntitySystem
|
||||
|
||||
// Yuck, this is way to hardcodey for my tastes
|
||||
// TODO blocking injection with a hardsuit should probably done with a cancellable event or something
|
||||
if (!injector.Comp.PierceArmor && _inventory.TryGetSlotEntity(target, "outerClothing", out var suit) && _tag.HasTag(suit.Value, "Hardsuit"))
|
||||
if (!injector.Comp.PierceArmor && _inventory.TryGetSlotEntity(target, "outerClothing", out var suit) && _tag.HasTag(suit.Value, HardsuitTag))
|
||||
{
|
||||
// Only show popup to attacker
|
||||
if (source != null)
|
||||
|
||||
@@ -259,7 +259,7 @@ public sealed class IPIntel
|
||||
{
|
||||
_chatManager.SendAdminAlert(Loc.GetString("admin-alert-ipintel-warning",
|
||||
("player", username),
|
||||
("percent", Math.Round(score))));
|
||||
("percent", score)));
|
||||
}
|
||||
|
||||
if (!decisionIsReject)
|
||||
@@ -269,7 +269,7 @@ public sealed class IPIntel
|
||||
{
|
||||
_chatManager.SendAdminAlert(Loc.GetString("admin-alert-ipintel-blocked",
|
||||
("player", username),
|
||||
("percent", Math.Round(score))));
|
||||
("percent", score)));
|
||||
}
|
||||
|
||||
return _rejectBad ? (true, Loc.GetString("ipintel-suspicious")) : (false, string.Empty);
|
||||
|
||||
@@ -5,6 +5,7 @@ using Content.Shared.Construction;
|
||||
using Content.Shared.Tag;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Construction.Commands;
|
||||
|
||||
@@ -13,6 +14,10 @@ public sealed class FixRotationsCommand : IConsoleCommand
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||
|
||||
private static readonly ProtoId<TagPrototype> ForceFixRotationsTag = "ForceFixRotations";
|
||||
private static readonly ProtoId<TagPrototype> ForceNoFixRotationsTag = "ForceNoFixRotations";
|
||||
private static readonly ProtoId<TagPrototype> DiagonalTag = "Diagonal";
|
||||
|
||||
// ReSharper disable once StringLiteralTypo
|
||||
public string Command => "fixrotations";
|
||||
public string Description => "Sets the rotation of all occluders, low walls and windows to south.";
|
||||
@@ -86,11 +91,11 @@ public sealed class FixRotationsCommand : IConsoleCommand
|
||||
// cables
|
||||
valid |= _entManager.HasComponent<CableComponent>(child);
|
||||
// anything else that might need this forced
|
||||
valid |= tagSystem.HasTag(child, "ForceFixRotations");
|
||||
valid |= tagSystem.HasTag(child, ForceFixRotationsTag);
|
||||
// override
|
||||
valid &= !tagSystem.HasTag(child, "ForceNoFixRotations");
|
||||
valid &= !tagSystem.HasTag(child, ForceNoFixRotationsTag);
|
||||
// remove diagonal entities as well
|
||||
valid &= !tagSystem.HasTag(child, "Diagonal");
|
||||
valid &= !tagSystem.HasTag(child, DiagonalTag);
|
||||
|
||||
if (!valid)
|
||||
continue;
|
||||
|
||||
@@ -4,7 +4,7 @@ using Content.Server.StationRecords.Systems;
|
||||
using Content.Shared.CriminalRecords;
|
||||
using Content.Shared.CriminalRecords.Components;
|
||||
using Content.Shared.CriminalRecords.Systems;
|
||||
using Content.Shared.Dataset;
|
||||
using Content.Shared.Random.Helpers;
|
||||
using Content.Shared.Security;
|
||||
using Content.Shared.StationRecords;
|
||||
using Robust.Shared.Prototypes;
|
||||
@@ -36,10 +36,10 @@ public sealed class CriminalRecordsHackerSystem : SharedCriminalRecordsHackerSys
|
||||
if (_station.GetOwningStation(ent) is not {} station)
|
||||
return;
|
||||
|
||||
var reasons = _proto.Index<DatasetPrototype>(ent.Comp.Reasons);
|
||||
var reasons = _proto.Index(ent.Comp.Reasons);
|
||||
foreach (var (key, record) in _records.GetRecordsOfType<CriminalRecord>(station))
|
||||
{
|
||||
var reason = _random.Pick(reasons.Values);
|
||||
var reason = _random.Pick(reasons);
|
||||
_criminalRecords.OverwriteStatus(new StationRecordKey(key, station), record, SecurityStatus.Wanted, reason);
|
||||
// no radio message since spam
|
||||
// no history since lazy and its easy to remove anyway
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Popups;
|
||||
using JetBrains.Annotations;
|
||||
@@ -25,7 +26,8 @@ public sealed partial class BurnBodyBehavior : IThresholdBehavior
|
||||
}
|
||||
}
|
||||
|
||||
sharedPopupSystem.PopupCoordinates(Loc.GetString("bodyburn-text-others", ("name", bodyId)), transformSystem.GetMoverCoordinates(bodyId), PopupType.LargeCaution);
|
||||
var bodyIdentity = Identity.Entity(bodyId, system.EntityManager);
|
||||
sharedPopupSystem.PopupCoordinates(Loc.GetString("bodyburn-text-others", ("name", bodyIdentity)), transformSystem.GetMoverCoordinates(bodyId), PopupType.LargeCaution);
|
||||
|
||||
system.EntityManager.QueueDeleteEntity(bodyId);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ using Robust.Shared.Serialization.Manager;
|
||||
using System.Numerics;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.Dragon;
|
||||
@@ -33,11 +34,20 @@ public sealed class DragonRiftSystem : EntitySystem
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<DragonRiftComponent, ComponentGetState>(OnGetState);
|
||||
SubscribeLocalEvent<DragonRiftComponent, ExaminedEvent>(OnExamined);
|
||||
SubscribeLocalEvent<DragonRiftComponent, AnchorStateChangedEvent>(OnAnchorChange);
|
||||
SubscribeLocalEvent<DragonRiftComponent, ComponentShutdown>(OnShutdown);
|
||||
}
|
||||
|
||||
private void OnGetState(Entity<DragonRiftComponent> ent, ref ComponentGetState args)
|
||||
{
|
||||
args.State = new DragonRiftComponentState
|
||||
{
|
||||
State = ent.Comp.State,
|
||||
};
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
@@ -62,6 +62,8 @@ public sealed class ElectrocutionSystem : SharedElectrocutionSystem
|
||||
[ValidatePrototypeId<DamageTypePrototype>]
|
||||
private const string DamageType = "Shock";
|
||||
|
||||
private static readonly ProtoId<TagPrototype> WindowTag = "Window";
|
||||
|
||||
// Multiply and shift the log scale for shock damage.
|
||||
private const float RecursiveDamageMultiplier = 0.75f;
|
||||
private const float RecursiveTimeMultiplier = 0.8f;
|
||||
@@ -139,7 +141,7 @@ public sealed class ElectrocutionSystem : SharedElectrocutionSystem
|
||||
{
|
||||
foreach (var entity in _entityLookup.GetLocalEntitiesIntersecting(tileRef.Value, flags: LookupFlags.StaticSundries))
|
||||
{
|
||||
if (_tag.HasTag(entity, "Window"))
|
||||
if (_tag.HasTag(entity, WindowTag))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Random;
|
||||
using InventoryComponent = Content.Shared.Inventory.InventoryComponent;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Flash
|
||||
{
|
||||
@@ -39,6 +40,8 @@ namespace Content.Server.Flash
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!;
|
||||
|
||||
private static readonly ProtoId<TagPrototype> TrashTag = "Trash";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -94,7 +97,7 @@ namespace Content.Server.Flash
|
||||
if (_charges.IsEmpty(uid, charges))
|
||||
{
|
||||
_appearance.SetData(uid, FlashVisuals.Burnt, true);
|
||||
_tag.AddTag(uid, "Trash");
|
||||
_tag.AddTag(uid, TrashTag);
|
||||
_popup.PopupEntity(Loc.GetString("flash-component-becomes-empty"), user);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ using Robust.Shared.Audio;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Timing;
|
||||
using Content.Server.Chemistry.Containers.EntitySystems;
|
||||
using Robust.Shared.Prototypes;
|
||||
// todo: remove this stinky LINQy
|
||||
|
||||
namespace Content.Server.Forensics
|
||||
@@ -33,6 +34,8 @@ namespace Content.Server.Forensics
|
||||
[Dependency] private readonly ForensicsSystem _forensicsSystem = default!;
|
||||
[Dependency] private readonly TagSystem _tag = default!;
|
||||
|
||||
private static readonly ProtoId<TagPrototype> DNASolutionScannableTag = "DNASolutionScannable";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -86,7 +89,7 @@ namespace Content.Server.Forensics
|
||||
scanner.Residues = forensics.Residues.ToList();
|
||||
}
|
||||
|
||||
if (_tag.HasTag(args.Args.Target.Value, "DNASolutionScannable"))
|
||||
if (_tag.HasTag(args.Args.Target.Value, DNASolutionScannableTag))
|
||||
{
|
||||
scanner.SolutionDNAs = _forensicsSystem.GetSolutionsDNA(args.Args.Target.Value);
|
||||
} else
|
||||
|
||||
@@ -9,6 +9,7 @@ using Content.Shared.Mobs.Systems;
|
||||
using Content.Shared.Survivor.Components;
|
||||
using Content.Shared.Tag;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.GameTicking.Rules;
|
||||
|
||||
@@ -22,6 +23,8 @@ public sealed class SurvivorRuleSystem : GameRuleSystem<SurvivorRuleComponent>
|
||||
[Dependency] private readonly TagSystem _tag = default!;
|
||||
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||
|
||||
private static readonly ProtoId<TagPrototype> InvalidForSurvivorAntagTag = "InvalidForSurvivorAntag";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -44,7 +47,7 @@ public sealed class SurvivorRuleSystem : GameRuleSystem<SurvivorRuleComponent>
|
||||
var mind = humanMind.Owner;
|
||||
var ent = humanMind.Comp.OwnedEntity.Value;
|
||||
|
||||
if (HasComp<SurvivorComponent>(mind) || _tag.HasTag(mind, "InvalidForSurvivorAntag"))
|
||||
if (HasComp<SurvivorComponent>(mind) || _tag.HasTag(mind, InvalidForSurvivorAntagTag))
|
||||
continue;
|
||||
|
||||
EnsureComp<SurvivorComponent>(mind);
|
||||
|
||||
@@ -72,6 +72,8 @@ namespace Content.Server.Ghost
|
||||
private EntityQuery<GhostComponent> _ghostQuery;
|
||||
private EntityQuery<PhysicsComponent> _physicsQuery;
|
||||
|
||||
private static readonly ProtoId<TagPrototype> AllowGhostShownByEventTag = "AllowGhostShownByEvent";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -403,7 +405,7 @@ namespace Content.Server.Ghost
|
||||
var entityQuery = EntityQueryEnumerator<GhostComponent, VisibilityComponent>();
|
||||
while (entityQuery.MoveNext(out var uid, out var _, out var vis))
|
||||
{
|
||||
if (!_tag.HasTag(uid, "AllowGhostShownByEvent"))
|
||||
if (!_tag.HasTag(uid, AllowGhostShownByEventTag))
|
||||
continue;
|
||||
|
||||
if (visible)
|
||||
|
||||
@@ -73,6 +73,9 @@ namespace Content.Server.Kitchen.EntitySystems
|
||||
[ValidatePrototypeId<EntityPrototype>]
|
||||
private const string MalfunctionSpark = "Spark";
|
||||
|
||||
private static readonly ProtoId<TagPrototype> MetalTag = "Metal";
|
||||
private static readonly ProtoId<TagPrototype> PlasticTag = "Plastic";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -550,12 +553,12 @@ namespace Content.Server.Kitchen.EntitySystems
|
||||
return;
|
||||
}
|
||||
|
||||
if (_tag.HasTag(item, "Metal"))
|
||||
if (_tag.HasTag(item, MetalTag))
|
||||
{
|
||||
malfunctioning = true;
|
||||
}
|
||||
|
||||
if (_tag.HasTag(item, "Plastic"))
|
||||
if (_tag.HasTag(item, PlasticTag))
|
||||
{
|
||||
var junk = Spawn(component.BadRecipeEntityId, Transform(uid).Coordinates);
|
||||
_container.Insert(junk, component.Storage);
|
||||
|
||||
@@ -10,6 +10,7 @@ using Content.Shared.Verbs;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.Light.EntitySystems
|
||||
@@ -24,6 +25,8 @@ namespace Content.Server.Light.EntitySystems
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
[Dependency] private readonly MetaDataSystem _metaData = default!;
|
||||
|
||||
private static readonly ProtoId<TagPrototype> TrashTag = "Trash";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -69,7 +72,7 @@ namespace Content.Server.Light.EntitySystems
|
||||
_metaData.SetEntityName(ent, Loc.GetString(component.SpentName), meta);
|
||||
_metaData.SetEntityDescription(ent, Loc.GetString(component.SpentDesc), meta);
|
||||
|
||||
_tagSystem.AddTag(ent, "Trash");
|
||||
_tagSystem.AddTag(ent, TrashTag);
|
||||
|
||||
UpdateSounds(ent);
|
||||
UpdateVisualizer(ent);
|
||||
|
||||
@@ -16,6 +16,8 @@ public sealed class MagicSystem : SharedMagicSystem
|
||||
[Dependency] private readonly TagSystem _tag = default!;
|
||||
[Dependency] private readonly SharedMindSystem _mind = default!;
|
||||
|
||||
private static readonly ProtoId<TagPrototype> InvalidForSurvivorAntagTag = "InvalidForSurvivorAntag";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -48,8 +50,8 @@ public sealed class MagicSystem : SharedMagicSystem
|
||||
if (!ev.MakeSurvivorAntagonist)
|
||||
return;
|
||||
|
||||
if (_mind.TryGetMind(ev.Performer, out var mind, out _) && !_tag.HasTag(mind, "InvalidForSurvivorAntag"))
|
||||
_tag.AddTag(mind, "InvalidForSurvivorAntag");
|
||||
if (_mind.TryGetMind(ev.Performer, out var mind, out _) && !_tag.HasTag(mind, InvalidForSurvivorAntagTag))
|
||||
_tag.AddTag(mind, InvalidForSurvivorAntagTag);
|
||||
|
||||
EntProtoId survivorRule = "Survivor";
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ using Content.Shared.MagicMirror;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Tag;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.MagicMirror;
|
||||
|
||||
@@ -27,6 +28,8 @@ public sealed class MagicMirrorSystem : SharedMagicMirrorSystem
|
||||
[Dependency] private readonly InventorySystem _inventory = default!;
|
||||
[Dependency] private readonly TagSystem _tagSystem = default!;
|
||||
|
||||
private static readonly ProtoId<TagPrototype> HidesHairTag = "HidesHair";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -59,7 +62,7 @@ public sealed class MagicMirrorSystem : SharedMagicMirrorSystem
|
||||
_popup.PopupEntity(
|
||||
component.Target == message.Actor
|
||||
? Loc.GetString("magic-mirror-blocked-by-hat-self")
|
||||
: Loc.GetString("magic-mirror-blocked-by-hat-self-target"),
|
||||
: Loc.GetString("magic-mirror-blocked-by-hat-self-target", ("target", Identity.Entity(message.Actor, EntityManager))),
|
||||
message.Actor,
|
||||
message.Actor,
|
||||
PopupType.Medium);
|
||||
@@ -95,7 +98,7 @@ public sealed class MagicMirrorSystem : SharedMagicMirrorSystem
|
||||
}
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("magic-mirror-change-slot-target", ("user", Identity.Name(message.Actor, EntityManager))), component.Target.Value, component.Target.Value, PopupType.Medium);
|
||||
_popup.PopupEntity(Loc.GetString("magic-mirror-change-slot-target", ("user", Identity.Entity(message.Actor, EntityManager))), component.Target.Value, component.Target.Value, PopupType.Medium);
|
||||
}
|
||||
|
||||
component.DoAfter = doAfterId;
|
||||
@@ -175,7 +178,7 @@ public sealed class MagicMirrorSystem : SharedMagicMirrorSystem
|
||||
}
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("magic-mirror-change-color-target", ("user", Identity.Name(message.Actor, EntityManager))), component.Target.Value, component.Target.Value, PopupType.Medium);
|
||||
_popup.PopupEntity(Loc.GetString("magic-mirror-change-color-target", ("user", Identity.Entity(message.Actor, EntityManager))), component.Target.Value, component.Target.Value, PopupType.Medium);
|
||||
}
|
||||
|
||||
component.DoAfter = doAfterId;
|
||||
@@ -253,7 +256,7 @@ public sealed class MagicMirrorSystem : SharedMagicMirrorSystem
|
||||
}
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("magic-mirror-remove-slot-target", ("user", Identity.Name(message.Actor, EntityManager))), component.Target.Value, component.Target.Value, PopupType.Medium);
|
||||
_popup.PopupEntity(Loc.GetString("magic-mirror-remove-slot-target", ("user", Identity.Entity(message.Actor, EntityManager))), component.Target.Value, component.Target.Value, PopupType.Medium);
|
||||
}
|
||||
|
||||
component.DoAfter = doAfterId;
|
||||
@@ -331,7 +334,7 @@ public sealed class MagicMirrorSystem : SharedMagicMirrorSystem
|
||||
}
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("magic-mirror-add-slot-target", ("user", Identity.Name(message.Actor, EntityManager))), component.Target.Value, component.Target.Value, PopupType.Medium);
|
||||
_popup.PopupEntity(Loc.GetString("magic-mirror-add-slot-target", ("user", Identity.Entity(message.Actor, EntityManager))), component.Target.Value, component.Target.Value, PopupType.Medium);
|
||||
}
|
||||
|
||||
component.DoAfter = doAfterId;
|
||||
@@ -391,7 +394,7 @@ public sealed class MagicMirrorSystem : SharedMagicMirrorSystem
|
||||
var slots = _inventory.GetSlotEnumerator((target, inventoryComp), SlotFlags.WITHOUT_POCKET);
|
||||
while (slots.MoveNext(out var slot))
|
||||
{
|
||||
if (slot.ContainedEntity != null && _tagSystem.HasTag(slot.ContainedEntity.Value, "HidesHair"))
|
||||
if (slot.ContainedEntity != null && _tagSystem.HasTag(slot.ContainedEntity.Value, HidesHairTag))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
51
Content.Server/Movement/Systems/MobCollisionSystem.cs
Normal file
51
Content.Server/Movement/Systems/MobCollisionSystem.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using System.Numerics;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Movement.Components;
|
||||
using Content.Shared.Movement.Systems;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Server.Movement.Systems;
|
||||
|
||||
public sealed class MobCollisionSystem : SharedMobCollisionSystem
|
||||
{
|
||||
private EntityQuery<ActorComponent> _actorQuery;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
_actorQuery = GetEntityQuery<ActorComponent>();
|
||||
SubscribeLocalEvent<MobCollisionComponent, MobCollisionMessage>(OnServerMobCollision);
|
||||
}
|
||||
|
||||
private void OnServerMobCollision(Entity<MobCollisionComponent> ent, ref MobCollisionMessage args)
|
||||
{
|
||||
MoveMob((ent.Owner, ent.Comp, Transform(ent.Owner)), args.Direction, args.SpeedModifier);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
if (!CfgManager.GetCVar(CCVars.MovementMobPushing))
|
||||
return;
|
||||
|
||||
var query = EntityQueryEnumerator<MobCollisionComponent>();
|
||||
|
||||
while (query.MoveNext(out var uid, out var comp))
|
||||
{
|
||||
if (_actorQuery.HasComp(uid) || !PhysicsQuery.TryComp(uid, out var physics))
|
||||
continue;
|
||||
|
||||
HandleCollisions((uid, comp, physics), frameTime);
|
||||
}
|
||||
|
||||
base.Update(frameTime);
|
||||
}
|
||||
|
||||
protected override void RaiseCollisionEvent(EntityUid uid, Vector2 direction, float speedMod)
|
||||
{
|
||||
RaiseLocalEvent(uid, new MobCollisionMessage()
|
||||
{
|
||||
Direction = direction,
|
||||
SpeedModifier = speedMod,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -86,7 +86,7 @@ public sealed partial class MoveToOperator : HTNOperator, IHtnConditionalShutdow
|
||||
return (false, null);
|
||||
|
||||
if (!_entManager.TryGetComponent<MapGridComponent>(xform.GridUid, out var ownerGrid) ||
|
||||
!_entManager.TryGetComponent<MapGridComponent>(targetCoordinates.GetGridUid(_entManager), out var targetGrid))
|
||||
!_entManager.TryGetComponent<MapGridComponent>(_transform.GetGrid(targetCoordinates), out var targetGrid))
|
||||
{
|
||||
return (false, null);
|
||||
}
|
||||
@@ -155,8 +155,8 @@ public sealed partial class MoveToOperator : HTNOperator, IHtnConditionalShutdow
|
||||
{
|
||||
if (blackboard.TryGetValue<EntityCoordinates>(NPCBlackboard.OwnerCoordinates, out var coordinates, _entManager))
|
||||
{
|
||||
var mapCoords = coordinates.ToMap(_entManager, _transform);
|
||||
_steering.PrunePath(uid, mapCoords, targetCoordinates.ToMapPos(_entManager, _transform) - mapCoords.Position, result.Path);
|
||||
var mapCoords = _transform.ToMapCoordinates(coordinates);
|
||||
_steering.PrunePath(uid, mapCoords, _transform.ToMapCoordinates(targetCoordinates).Position - mapCoords.Position, result.Path);
|
||||
}
|
||||
|
||||
comp.CurrentPath = new Queue<PathPoly>(result.Path);
|
||||
|
||||
@@ -2,10 +2,6 @@ using System.Diagnostics.CodeAnalysis;
|
||||
using System.Numerics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Server.Destructible;
|
||||
using Content.Shared.Access.Components;
|
||||
using Content.Shared.Climbing.Components;
|
||||
using Content.Shared.Doors.Components;
|
||||
using Content.Shared.NPC;
|
||||
using Content.Shared.Physics;
|
||||
using Robust.Shared.Collections;
|
||||
@@ -281,7 +277,7 @@ public sealed partial class PathfindingSystem
|
||||
var gridUid = ev.Component.GridUid;
|
||||
var oldGridUid = ev.OldPosition.EntityId == ev.NewPosition.EntityId
|
||||
? gridUid
|
||||
: ev.OldPosition.GetGridUid(EntityManager);
|
||||
: _transform.GetGrid((ev.Entity.Owner, ev.Component));
|
||||
|
||||
if (oldGridUid != null && oldGridUid != gridUid)
|
||||
{
|
||||
@@ -395,7 +391,7 @@ public sealed partial class PathfindingSystem
|
||||
|
||||
private Vector2i GetOrigin(EntityCoordinates coordinates, EntityUid gridUid)
|
||||
{
|
||||
var localPos = Vector2.Transform(coordinates.ToMapPos(EntityManager, _transform), _transform.GetInvWorldMatrix(gridUid));
|
||||
var localPos = Vector2.Transform(_transform.ToMapCoordinates(coordinates).Position, _transform.GetInvWorldMatrix(gridUid));
|
||||
return new Vector2i((int) Math.Floor(localPos.X / ChunkSize), (int) Math.Floor(localPos.Y / ChunkSize));
|
||||
}
|
||||
|
||||
|
||||
@@ -461,7 +461,7 @@ public sealed partial class NPCSteeringSystem : SharedNPCSteeringSystem
|
||||
return;
|
||||
}
|
||||
|
||||
var targetPos = steering.Coordinates.ToMap(EntityManager, _transform);
|
||||
var targetPos = _transform.ToMapCoordinates(steering.Coordinates);
|
||||
var ourPos = _transform.GetMapCoordinates(uid, xform: xform);
|
||||
|
||||
PrunePath(uid, ourPos, targetPos.Position - ourPos.Position, result.Path);
|
||||
|
||||
@@ -3,6 +3,7 @@ using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Chemistry.Components.SolutionManager;
|
||||
using Content.Shared.Chemistry.EntitySystems;
|
||||
using Content.Shared.Tag;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Nutrition.EntitySystems
|
||||
{
|
||||
@@ -11,6 +12,8 @@ namespace Content.Server.Nutrition.EntitySystems
|
||||
[Dependency] private readonly SharedSolutionContainerSystem _solutionContainerSystem = default!;
|
||||
[Dependency] private readonly TagSystem _tagSystem = default!;
|
||||
|
||||
private static readonly ProtoId<TagPrototype> TrashTag = "Trash";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -41,11 +44,11 @@ namespace Content.Server.Nutrition.EntitySystems
|
||||
{
|
||||
if (solution.Volume <= 0)
|
||||
{
|
||||
_tagSystem.AddTag(entity.Owner, "Trash");
|
||||
_tagSystem.AddTag(entity.Owner, TrashTag);
|
||||
return;
|
||||
}
|
||||
if (_tagSystem.HasTag(entity.Owner, "Trash"))
|
||||
_tagSystem.RemoveTag(entity.Owner, "Trash");
|
||||
|
||||
_tagSystem.RemoveTag(entity.Owner, TrashTag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ using Robust.Shared.Serialization.Manager;
|
||||
using Robust.Shared.Utility;
|
||||
using System.Linq;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Payload.EntitySystems;
|
||||
|
||||
@@ -23,6 +24,8 @@ public sealed class PayloadSystem : EntitySystem
|
||||
[Dependency] private readonly IComponentFactory _componentFactory = default!;
|
||||
[Dependency] private readonly ISerializationManager _serializationManager = default!;
|
||||
|
||||
private static readonly ProtoId<TagPrototype> PayloadTag = "Payload";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -44,7 +47,7 @@ public sealed class PayloadSystem : EntitySystem
|
||||
{
|
||||
foreach (var entity in container.ContainedEntities)
|
||||
{
|
||||
if (_tagSystem.HasTag(entity, "Payload"))
|
||||
if (_tagSystem.HasTag(entity, PayloadTag))
|
||||
yield return entity;
|
||||
}
|
||||
}
|
||||
@@ -71,7 +74,7 @@ public sealed class PayloadSystem : EntitySystem
|
||||
return;
|
||||
|
||||
// Ensure we don't enter a trigger-loop
|
||||
DebugTools.Assert(!_tagSystem.HasTag(uid, "Payload"));
|
||||
DebugTools.Assert(!_tagSystem.HasTag(uid, PayloadTag));
|
||||
|
||||
RaiseLocalEvent(parent, args, false);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
using System.Numerics;
|
||||
using Content.Shared.Procedural;
|
||||
using Content.Shared.Tag;
|
||||
using Robust.Shared.Collections;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Physics.Components;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Procedural.DungeonJob;
|
||||
|
||||
@@ -12,13 +14,15 @@ public sealed partial class DungeonJob
|
||||
* Run after the main dungeon generation
|
||||
*/
|
||||
|
||||
private static readonly ProtoId<TagPrototype> WallTag = "Wall";
|
||||
|
||||
private bool HasWall(Vector2i tile)
|
||||
{
|
||||
var anchored = _maps.GetAnchoredEntitiesEnumerator(_gridUid, _grid, tile);
|
||||
|
||||
while (anchored.MoveNext(out var uid))
|
||||
{
|
||||
if (_tags.HasTag(uid.Value, "Wall"))
|
||||
if (_tags.HasTag(uid.Value, WallTag))
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ using Robust.Shared.Physics.Components;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Content.Shared.Whitelist;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Revenant.EntitySystems;
|
||||
|
||||
@@ -44,6 +45,8 @@ public sealed partial class RevenantSystem
|
||||
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
|
||||
[Dependency] private readonly SharedMapSystem _mapSystem = default!;
|
||||
|
||||
private static readonly ProtoId<TagPrototype> WindowTag = "Window";
|
||||
|
||||
private void InitializeAbilities()
|
||||
{
|
||||
SubscribeLocalEvent<RevenantComponent, UserActivateInWorldEvent>(OnInteract);
|
||||
@@ -253,7 +256,7 @@ public sealed partial class RevenantSystem
|
||||
foreach (var ent in lookup)
|
||||
{
|
||||
//break windows
|
||||
if (tags.HasComponent(ent) && _tag.HasTag(ent, "Window"))
|
||||
if (tags.HasComponent(ent) && _tag.HasTag(ent, WindowTag))
|
||||
{
|
||||
//hardcoded damage specifiers til i die.
|
||||
var dspec = new DamageSpecifier();
|
||||
|
||||
@@ -21,6 +21,7 @@ using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Utility;
|
||||
using Content.Shared.UserInterface;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Shuttles.Systems;
|
||||
|
||||
@@ -43,6 +44,8 @@ public sealed partial class ShuttleConsoleSystem : SharedShuttleConsoleSystem
|
||||
|
||||
private readonly HashSet<Entity<ShuttleConsoleComponent>> _consoles = new();
|
||||
|
||||
private static readonly ProtoId<TagPrototype> CanPilotTag = "CanPilot";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -168,7 +171,7 @@ public sealed partial class ShuttleConsoleSystem : SharedShuttleConsoleSystem
|
||||
|
||||
private bool TryPilot(EntityUid user, EntityUid uid)
|
||||
{
|
||||
if (!_tags.HasTag(user, "CanPilot") ||
|
||||
if (!_tags.HasTag(user, CanPilotTag) ||
|
||||
!TryComp<ShuttleConsoleComponent>(uid, out var component) ||
|
||||
!this.IsPowered(uid, EntityManager) ||
|
||||
!Transform(uid).Anchored ||
|
||||
|
||||
@@ -14,6 +14,7 @@ using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Physics.Components;
|
||||
using Robust.Shared.Physics.Events;
|
||||
using Robust.Shared.Physics.Systems;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server.Singularity.EntitySystems;
|
||||
@@ -36,6 +37,8 @@ public sealed class EventHorizonSystem : SharedEventHorizonSystem
|
||||
[Dependency] private readonly TagSystem _tagSystem = default!;
|
||||
#endregion Dependencies
|
||||
|
||||
private static readonly ProtoId<TagPrototype> HighRiskItemTag = "HighRiskItem";
|
||||
|
||||
private EntityQuery<PhysicsComponent> _physicsQuery;
|
||||
|
||||
public override void Initialize()
|
||||
@@ -127,7 +130,7 @@ public sealed class EventHorizonSystem : SharedEventHorizonSystem
|
||||
return;
|
||||
|
||||
if (HasComp<MindContainerComponent>(morsel)
|
||||
|| _tagSystem.HasTag(morsel, "HighRiskItem")
|
||||
|| _tagSystem.HasTag(morsel, HighRiskItemTag)
|
||||
|| HasComp<ContainmentFieldGeneratorComponent>(morsel))
|
||||
{
|
||||
_adminLogger.Add(LogType.EntityDelete, LogImpact.High, $"{ToPrettyString(morsel):player} entered the event horizon of {ToPrettyString(hungry)} and was deleted");
|
||||
|
||||
@@ -8,6 +8,7 @@ using Content.Shared.Interaction.Components;
|
||||
using Content.Shared.Storage;
|
||||
using Content.Shared.Tag;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server.Tools.Innate;
|
||||
@@ -22,6 +23,8 @@ public sealed class InnateToolSystem : EntitySystem
|
||||
[Dependency] private readonly SharedHandsSystem _sharedHandsSystem = default!;
|
||||
[Dependency] private readonly TagSystem _tagSystem = default!;
|
||||
|
||||
private static readonly ProtoId<TagPrototype> InnateDontDeleteTag = "InnateDontDelete";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -76,7 +79,7 @@ public sealed class InnateToolSystem : EntitySystem
|
||||
{
|
||||
foreach (var tool in component.ToolUids)
|
||||
{
|
||||
if (_tagSystem.HasTag(tool, "InnateDontDelete"))
|
||||
if (_tagSystem.HasTag(tool, InnateDontDeleteTag))
|
||||
{
|
||||
RemComp<UnremoveableComponent>(tool);
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ using Content.Shared.Traits.Assorted;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Content.Shared.Ghost.Roles.Components;
|
||||
using Content.Shared.Tag;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Zombies;
|
||||
|
||||
@@ -61,6 +62,8 @@ public sealed partial class ZombieSystem
|
||||
[Dependency] private readonly TagSystem _tag = default!;
|
||||
[Dependency] private readonly NameModifierSystem _nameMod = default!;
|
||||
|
||||
private static readonly ProtoId<TagPrototype> InvalidForGlobalSpawnSpellTag = "InvalidForGlobalSpawnSpell";
|
||||
|
||||
/// <summary>
|
||||
/// Handles an entity turning into a zombie when they die or go into crit
|
||||
/// </summary>
|
||||
@@ -290,6 +293,6 @@ public sealed partial class ZombieSystem
|
||||
|
||||
//Need to prevent them from getting an item, they have no hands.
|
||||
// Also prevents them from becoming a Survivor. They're undead.
|
||||
_tag.AddTag(target, "InvalidForGlobalSpawnSpell");
|
||||
_tag.AddTag(target, InvalidForGlobalSpawnSpellTag);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameStates;
|
||||
using Content.Shared.GameTicking;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Tag;
|
||||
using Robust.Shared.Collections;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
@@ -24,11 +25,14 @@ public sealed class AccessReaderSystem : EntitySystem
|
||||
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
[Dependency] private readonly EmagSystem _emag = default!;
|
||||
[Dependency] private readonly TagSystem _tag = default!;
|
||||
[Dependency] private readonly SharedGameTicker _gameTicker = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
|
||||
[Dependency] private readonly SharedStationRecordsSystem _recordsSystem = default!;
|
||||
|
||||
private static readonly ProtoId<TagPrototype> PreventAccessLoggingTag = "PreventAccessLogging";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -115,13 +119,13 @@ public sealed class AccessReaderSystem : EntitySystem
|
||||
var access = FindAccessTags(user, accessSources);
|
||||
FindStationRecordKeys(user, out var stationKeys, accessSources);
|
||||
|
||||
if (IsAllowed(access, stationKeys, target, reader))
|
||||
{
|
||||
LogAccess((target, reader), user);
|
||||
return true;
|
||||
}
|
||||
if (!IsAllowed(access, stationKeys, target, reader))
|
||||
return false;
|
||||
|
||||
return false;
|
||||
if (!_tag.HasTag(user, PreventAccessLoggingTag))
|
||||
LogAccess((target, reader), user);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool GetMainAccessReader(EntityUid uid, [NotNullWhen(true)] out Entity<AccessReaderComponent>? ent)
|
||||
|
||||
59
Content.Shared/CCVar/CCVars.Movement.cs
Normal file
59
Content.Shared/CCVar/CCVars.Movement.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.CCVar.CVarAccess;
|
||||
using Robust.Shared.Configuration;
|
||||
|
||||
namespace Content.Shared.CCVar;
|
||||
|
||||
public sealed partial class CCVars
|
||||
{
|
||||
/// <summary>
|
||||
/// Is mob pushing enabled.
|
||||
/// </summary>
|
||||
[CVarControl(AdminFlags.VarEdit)]
|
||||
public static readonly CVarDef<bool> MovementMobPushing =
|
||||
CVarDef.Create("movement.mob_pushing", false, CVar.SERVER | CVar.REPLICATED);
|
||||
|
||||
/// <summary>
|
||||
/// Can we push mobs not moving.
|
||||
/// </summary>
|
||||
[CVarControl(AdminFlags.VarEdit)]
|
||||
public static readonly CVarDef<bool> MovementPushingStatic =
|
||||
CVarDef.Create("movement.pushing_static", true, CVar.SERVER | CVar.REPLICATED);
|
||||
|
||||
/// <summary>
|
||||
/// Dot product for the pushed entity's velocity to a target entity's velocity before it gets moved.
|
||||
/// </summary>
|
||||
[CVarControl(AdminFlags.VarEdit)]
|
||||
public static readonly CVarDef<float> MovementPushingVelocityProduct =
|
||||
CVarDef.Create("movement.pushing_velocity_product", -1f, CVar.SERVER | CVar.REPLICATED);
|
||||
|
||||
/// <summary>
|
||||
/// Cap for how much an entity can be pushed per second.
|
||||
/// </summary>
|
||||
[CVarControl(AdminFlags.VarEdit)]
|
||||
public static readonly CVarDef<float> MovementPushingCap =
|
||||
CVarDef.Create("movement.pushing_cap", 100f, CVar.SERVER | CVar.REPLICATED);
|
||||
|
||||
/// <summary>
|
||||
/// Minimum pushing impulse per tick. If the value is below this it rounds to 0.
|
||||
/// This is an optimisation to avoid pushing small values that won't actually move the mobs.
|
||||
/// </summary>
|
||||
[CVarControl(AdminFlags.VarEdit)]
|
||||
public static readonly CVarDef<float> MovementMinimumPush =
|
||||
CVarDef.Create("movement.minimum_push", 0.1f, CVar.SERVER | CVar.REPLICATED);
|
||||
|
||||
// Really this just exists because hot reloading is cooked on rider.
|
||||
/// <summary>
|
||||
/// Penetration depth cap for considering mob collisions.
|
||||
/// </summary>
|
||||
[CVarControl(AdminFlags.VarEdit)]
|
||||
public static readonly CVarDef<float> MovementPenetrationCap =
|
||||
CVarDef.Create("movement.penetration_cap", 0.3f, CVar.SERVER | CVar.REPLICATED);
|
||||
|
||||
/// <summary>
|
||||
/// Based on the mass difference multiplies the push amount by this proportionally.
|
||||
/// </summary>
|
||||
[CVarControl(AdminFlags.VarEdit)]
|
||||
public static readonly CVarDef<float> MovementPushMassCap =
|
||||
CVarDef.Create("movement.push_mass_cap", 1.75f, CVar.SERVER | CVar.REPLICATED);
|
||||
}
|
||||
@@ -15,13 +15,4 @@ public sealed partial class CCVars
|
||||
|
||||
public static readonly CVarDef<float> StopSpeed =
|
||||
CVarDef.Create("physics.stop_speed", 0.1f, CVar.ARCHIVE | CVar.REPLICATED | CVar.SERVER);
|
||||
|
||||
/// <summary>
|
||||
/// Whether mobs can push objects like lockers.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Technically client doesn't need to know about it but this may prevent a bug in the distant future so it stays.
|
||||
/// </remarks>
|
||||
public static readonly CVarDef<bool> MobPushing =
|
||||
CVarDef.Create("physics.mob_pushing", false, CVar.REPLICATED | CVar.SERVER);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ public abstract class SharedChameleonClothingSystem : EntitySystem
|
||||
[Dependency] private readonly TagSystem _tag = default!;
|
||||
[Dependency] protected readonly SharedUserInterfaceSystem UI = default!;
|
||||
|
||||
private static readonly ProtoId<TagPrototype> WhitelistChameleonTag = "WhitelistChameleon";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -124,7 +126,7 @@ public abstract class SharedChameleonClothingSystem : EntitySystem
|
||||
return false;
|
||||
|
||||
// check if it is marked as valid chameleon target
|
||||
if (!proto.TryGetComponent(out TagComponent? tag, _factory) || !_tag.HasTag(tag, "WhitelistChameleon"))
|
||||
if (!proto.TryGetComponent(out TagComponent? tag, _factory) || !_tag.HasTag(tag, WhitelistChameleonTag))
|
||||
return false;
|
||||
|
||||
if (requiredTag != null && !_tag.HasTag(tag, requiredTag))
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
using Content.Shared.Maps;
|
||||
using Content.Shared.Maps;
|
||||
using Content.Shared.Tag;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared.Construction.Conditions
|
||||
{
|
||||
@@ -9,6 +10,8 @@ namespace Content.Shared.Construction.Conditions
|
||||
[DataDefinition]
|
||||
public sealed partial class NoWindowsInTile : IConstructionCondition
|
||||
{
|
||||
private static readonly ProtoId<TagPrototype> WindowTag = "Window";
|
||||
|
||||
public bool Condition(EntityUid user, EntityCoordinates location, Direction direction)
|
||||
{
|
||||
var entManager = IoCManager.Resolve<IEntityManager>();
|
||||
@@ -17,7 +20,7 @@ namespace Content.Shared.Construction.Conditions
|
||||
|
||||
foreach (var entity in location.GetEntitiesInTile(LookupFlags.Static))
|
||||
{
|
||||
if (tagSystem.HasTag(entity, "Window"))
|
||||
if (tagSystem.HasTag(entity, WindowTag))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ using JetBrains.Annotations;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Physics.Systems;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared.Construction.Conditions
|
||||
@@ -14,6 +15,8 @@ namespace Content.Shared.Construction.Conditions
|
||||
[DataDefinition]
|
||||
public sealed partial class WallmountCondition : IConstructionCondition
|
||||
{
|
||||
private static readonly ProtoId<TagPrototype> WallTag = "Wall";
|
||||
|
||||
public bool Condition(EntityUid user, EntityCoordinates location, Direction direction)
|
||||
{
|
||||
var entManager = IoCManager.Resolve<IEntityManager>();
|
||||
@@ -42,7 +45,7 @@ namespace Content.Shared.Construction.Conditions
|
||||
var tagSystem = entManager.System<TagSystem>();
|
||||
|
||||
var userToObjRaycastResults = physics.IntersectRayWithPredicate(entManager.GetComponent<TransformComponent>(user).MapID, rUserToObj, maxLength: length,
|
||||
predicate: (e) => !tagSystem.HasTag(e, "Wall"));
|
||||
predicate: (e) => !tagSystem.HasTag(e, WallTag));
|
||||
|
||||
var targetWall = userToObjRaycastResults.FirstOrNull();
|
||||
|
||||
@@ -53,7 +56,7 @@ namespace Content.Shared.Construction.Conditions
|
||||
// check that we didn't try to build wallmount that facing another adjacent wall
|
||||
var rAdjWall = new CollisionRay(objWorldPosition, directionWithOffset.Normalized(), (int) CollisionGroup.Impassable);
|
||||
var adjWallRaycastResults = physics.IntersectRayWithPredicate(entManager.GetComponent<TransformComponent>(user).MapID, rAdjWall, maxLength: 0.5f,
|
||||
predicate: e => e == targetWall.Value.HitEntity || !tagSystem.HasTag(e, "Wall"));
|
||||
predicate: e => e == targetWall.Value.HitEntity || !tagSystem.HasTag(e, WallTag));
|
||||
|
||||
return !adjWallRaycastResults.Any();
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ using Content.Shared.Tag;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared.Delivery;
|
||||
|
||||
@@ -30,6 +31,9 @@ public abstract class SharedDeliverySystem : EntitySystem
|
||||
[Dependency] private readonly SharedHandsSystem _hands = default!;
|
||||
[Dependency] private readonly NameModifierSystem _nameModifier = default!;
|
||||
|
||||
private static readonly ProtoId<TagPrototype> TrashTag = "Trash";
|
||||
private static readonly ProtoId<TagPrototype> RecyclableTag = "Recyclable";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -129,7 +133,7 @@ public abstract class SharedDeliverySystem : EntitySystem
|
||||
ent.Comp.IsOpened = true;
|
||||
_appearance.SetData(ent, DeliveryVisuals.IsTrash, ent.Comp.IsOpened);
|
||||
|
||||
_tag.AddTags(ent, "Trash", "Recyclable");
|
||||
_tag.AddTags(ent, TrashTag, RecyclableTag);
|
||||
EnsureComp<SpaceGarbageComponent>(ent);
|
||||
RemComp<StealTargetComponent>(ent); // opened mail should not count for the objective
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ using Content.Shared.Damage;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Tag;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
@@ -23,6 +24,8 @@ public abstract partial class SharedDoAfterSystem : EntitySystem
|
||||
/// </summary>
|
||||
private static readonly TimeSpan ExcessTime = TimeSpan.FromSeconds(0.5f);
|
||||
|
||||
private static readonly ProtoId<TagPrototype> InstantDoAftersTag = "InstantDoAfters";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -233,7 +236,7 @@ public abstract partial class SharedDoAfterSystem : EntitySystem
|
||||
|
||||
// TODO DO AFTER
|
||||
// Why does this tag exist? Just make this a bool on the component?
|
||||
if (args.Delay <= TimeSpan.Zero || _tag.HasTag(args.User, "InstantDoAfters"))
|
||||
if (args.Delay <= TimeSpan.Zero || _tag.HasTag(args.User, InstantDoAftersTag))
|
||||
{
|
||||
RaiseDoAfterEvents(doAfter, comp);
|
||||
// We don't store instant do-afters. This is just a lazy way of hiding them from client-side visuals.
|
||||
|
||||
@@ -18,6 +18,7 @@ using Robust.Shared.Network;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Physics.Systems;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared.Follower;
|
||||
@@ -32,6 +33,8 @@ public sealed class FollowerSystem : EntitySystem
|
||||
[Dependency] private readonly INetManager _netMan = default!;
|
||||
[Dependency] private readonly ISharedAdminManager _adminManager = default!;
|
||||
|
||||
private static readonly ProtoId<TagPrototype> ForceableFollowTag = "ForceableFollow";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -106,7 +109,7 @@ public sealed class FollowerSystem : EntitySystem
|
||||
ev.Verbs.Add(verb);
|
||||
}
|
||||
|
||||
if (_tagSystem.HasTag(ev.Target, "ForceableFollow"))
|
||||
if (_tagSystem.HasTag(ev.Target, ForceableFollowTag))
|
||||
{
|
||||
if (!ev.CanAccess || !ev.CanInteract)
|
||||
return;
|
||||
|
||||
@@ -6,12 +6,16 @@ using Content.Shared.Inventory.VirtualItem;
|
||||
using Content.Shared.Tag;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared.Hands.EntitySystems;
|
||||
|
||||
public abstract partial class SharedHandsSystem
|
||||
{
|
||||
[Dependency] private readonly TagSystem _tagSystem = default!;
|
||||
|
||||
private static readonly ProtoId<TagPrototype> BypassDropChecksTag = "BypassDropChecks";
|
||||
|
||||
private void InitializeDrop()
|
||||
{
|
||||
SubscribeLocalEvent<HandsComponent, EntRemovedFromContainerMessage>(HandleEntityRemoved);
|
||||
@@ -37,7 +41,7 @@ public abstract partial class SharedHandsSystem
|
||||
private bool ShouldIgnoreRestrictions(EntityUid user)
|
||||
{
|
||||
//Checks if the Entity is something that shouldn't care about drop distance or walls ie Aghost
|
||||
return !_tagSystem.HasTag(user, "BypassDropChecks");
|
||||
return !_tagSystem.HasTag(user, BypassDropChecksTag);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -7,6 +7,7 @@ using Content.Shared.Tag;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Prototypes;
|
||||
using System.Linq;
|
||||
|
||||
namespace Content.Shared.Implants;
|
||||
@@ -21,6 +22,9 @@ public abstract class SharedSubdermalImplantSystem : EntitySystem
|
||||
|
||||
public const string BaseStorageId = "storagebase";
|
||||
|
||||
private static readonly ProtoId<TagPrototype> MicroBombTag = "MicroBomb";
|
||||
private static readonly ProtoId<TagPrototype> MacroBombTag = "MacroBomb";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<SubdermalImplantComponent, EntGotInsertedIntoContainerMessage>(OnInsert);
|
||||
@@ -43,11 +47,11 @@ public abstract class SharedSubdermalImplantSystem : EntitySystem
|
||||
}
|
||||
|
||||
//replace micro bomb with macro bomb
|
||||
if (_container.TryGetContainer(component.ImplantedEntity.Value, ImplanterComponent.ImplantSlotId, out var implantContainer) && _tag.HasTag(uid, "MacroBomb"))
|
||||
if (_container.TryGetContainer(component.ImplantedEntity.Value, ImplanterComponent.ImplantSlotId, out var implantContainer) && _tag.HasTag(uid, MacroBombTag))
|
||||
{
|
||||
foreach (var implant in implantContainer.ContainedEntities)
|
||||
{
|
||||
if (_tag.HasTag(implant, "MicroBomb"))
|
||||
if (_tag.HasTag(implant, MicroBombTag))
|
||||
{
|
||||
_container.Remove(implant, implantContainer);
|
||||
QueueDel(implant);
|
||||
|
||||
@@ -37,6 +37,7 @@ using Robust.Shared.Physics;
|
||||
using Robust.Shared.Physics.Components;
|
||||
using Robust.Shared.Physics.Systems;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
@@ -87,6 +88,8 @@ namespace Content.Shared.Interaction
|
||||
public const float MaxRaycastRange = 100f;
|
||||
public const string RateLimitKey = "Interaction";
|
||||
|
||||
private static readonly ProtoId<TagPrototype> BypassInteractionRangeChecksTag = "BypassInteractionRangeChecks";
|
||||
|
||||
public delegate bool Ignored(EntityUid entity);
|
||||
|
||||
public override void Initialize()
|
||||
@@ -318,7 +321,7 @@ namespace Content.Shared.Interaction
|
||||
{
|
||||
// This is for Admin/mapping convenience. If ever there are other ghosts that can still interact, this check
|
||||
// might need to be more selective.
|
||||
return !_tagSystem.HasTag(user, "BypassInteractionRangeChecks");
|
||||
return !_tagSystem.HasTag(user, BypassInteractionRangeChecksTag);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -65,6 +65,8 @@ public abstract class SharedMagicSystem : EntitySystem
|
||||
[Dependency] private readonly SharedMindSystem _mind = default!;
|
||||
[Dependency] private readonly SharedStunSystem _stun = default!;
|
||||
|
||||
private static readonly ProtoId<TagPrototype> InvalidForGlobalSpawnSpellTag = "InvalidForGlobalSpawnSpell";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -484,7 +486,7 @@ public abstract class SharedMagicSystem : EntitySystem
|
||||
|
||||
var ent = human.Comp.OwnedEntity.Value;
|
||||
|
||||
if (_tag.HasTag(ent, "InvalidForGlobalSpawnSpell"))
|
||||
if (_tag.HasTag(ent, InvalidForGlobalSpawnSpellTag))
|
||||
continue;
|
||||
|
||||
var mapCoords = _transform.GetMapCoordinates(ent);
|
||||
|
||||
60
Content.Shared/Movement/Components/MobCollisionComponent.cs
Normal file
60
Content.Shared/Movement/Components/MobCollisionComponent.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using System.Numerics;
|
||||
using Content.Shared.Movement.Systems;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Movement.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Handles mobs pushing against each other.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(fieldDeltas: true)]
|
||||
public sealed partial class MobCollisionComponent : Component
|
||||
{
|
||||
// If you want to tweak the feel of the pushing use SpeedModifier and Strength.
|
||||
// Strength goes both ways and affects how much the other mob is pushed by so controls static pushing a lot.
|
||||
// Speed mod affects your own mob primarily.
|
||||
|
||||
/// <summary>
|
||||
/// Is this mob currently colliding? Used for SpeedModifier.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public bool Colliding;
|
||||
|
||||
// TODO: I hate this but also I couldn't quite figure out a way to avoid having to dirty it every tick.
|
||||
// The issue is it's a time target that changes constantly so we can't just use a timespan.
|
||||
// However that doesn't mean it should be modified every tick if we're still colliding.
|
||||
|
||||
/// <summary>
|
||||
/// Buffer time for <see cref="SpeedModifier"/> to keep applying after the entities are no longer colliding.
|
||||
/// Without this you will get jittering unless you are very specific with your values.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public float BufferAccumulator = SharedMobCollisionSystem.BufferTime;
|
||||
|
||||
/// <summary>
|
||||
/// The speed modifier for mobs currently pushing.
|
||||
/// By setting this low you can ensure you don't have to set the push-strength too high if you can push static entities.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public float SpeedModifier = 1f;
|
||||
|
||||
[DataField, AutoNetworkedField]
|
||||
public float MinimumSpeedModifier = 0.35f;
|
||||
|
||||
/// <summary>
|
||||
/// Strength of the pushback for entities. This is combined between the 2 entities being pushed.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public float Strength = 50f;
|
||||
|
||||
// Yes I know, I will deal with it if I ever refactor collision layers due to misuse.
|
||||
// If anything it probably needs some assurance on mobcollisionsystem for it.
|
||||
/// <summary>
|
||||
/// Fixture to listen to for mob collisions.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public string FixtureId = "flammable";
|
||||
|
||||
[DataField, AutoNetworkedField]
|
||||
public Vector2 Direction;
|
||||
}
|
||||
338
Content.Shared/Movement/Systems/SharedMobCollisionSystem.cs
Normal file
338
Content.Shared/Movement/Systems/SharedMobCollisionSystem.cs
Normal file
@@ -0,0 +1,338 @@
|
||||
using System.Numerics;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Movement.Components;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Physics.Components;
|
||||
using Robust.Shared.Physics.Systems;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared.Movement.Systems;
|
||||
|
||||
public abstract class SharedMobCollisionSystem : EntitySystem
|
||||
{
|
||||
[Dependency] protected readonly IConfigurationManager CfgManager = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly MovementSpeedModifierSystem _moveMod = default!;
|
||||
[Dependency] protected readonly SharedPhysicsSystem Physics = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _xformSystem = default!;
|
||||
|
||||
protected EntityQuery<MobCollisionComponent> MobQuery;
|
||||
protected EntityQuery<PhysicsComponent> PhysicsQuery;
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="CCVars.MovementPushingCap"/>
|
||||
/// </summary>
|
||||
private float _pushingCap;
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="CCVars.MovementPushingVelocityProduct"/>
|
||||
/// </summary>
|
||||
private float _pushingDotProduct;
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="CCVars.MovementMinimumPush"/>
|
||||
/// </summary>
|
||||
private float _minimumPushSquared = 0.01f;
|
||||
|
||||
private float _penCap;
|
||||
|
||||
/// <summary>
|
||||
/// Time after we stop colliding with another mob before adjusting the movespeedmodifier.
|
||||
/// This is required so if we stop colliding for a frame we don't fully reset and get jerky movement.
|
||||
/// </summary>
|
||||
public const float BufferTime = 0.2f;
|
||||
|
||||
private float _massDiffCap;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
UpdatePushCap();
|
||||
Subs.CVar(CfgManager, CVars.NetTickrate, _ => UpdatePushCap());
|
||||
Subs.CVar(CfgManager, CCVars.MovementMinimumPush, val => _minimumPushSquared = val * val, true);
|
||||
Subs.CVar(CfgManager, CCVars.MovementPenetrationCap, val => _penCap = val, true);
|
||||
Subs.CVar(CfgManager, CCVars.MovementPushingCap, _ => UpdatePushCap());
|
||||
Subs.CVar(CfgManager, CCVars.MovementPushingVelocityProduct,
|
||||
value =>
|
||||
{
|
||||
_pushingDotProduct = value;
|
||||
}, true);
|
||||
Subs.CVar(CfgManager, CCVars.MovementPushMassCap, val => _massDiffCap = val, true);
|
||||
|
||||
MobQuery = GetEntityQuery<MobCollisionComponent>();
|
||||
PhysicsQuery = GetEntityQuery<PhysicsComponent>();
|
||||
SubscribeAllEvent<MobCollisionMessage>(OnCollision);
|
||||
SubscribeLocalEvent<MobCollisionComponent, RefreshMovementSpeedModifiersEvent>(OnMoveModifier);
|
||||
|
||||
UpdatesBefore.Add(typeof(SharedPhysicsSystem));
|
||||
}
|
||||
|
||||
private void UpdatePushCap()
|
||||
{
|
||||
_pushingCap = (1f / CfgManager.GetCVar(CVars.NetTickrate)) * CfgManager.GetCVar(CCVars.MovementPushingCap);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
var query = AllEntityQuery<MobCollisionComponent>();
|
||||
|
||||
while (query.MoveNext(out var uid, out var comp))
|
||||
{
|
||||
if (!comp.Colliding)
|
||||
continue;
|
||||
|
||||
comp.BufferAccumulator -= frameTime;
|
||||
DirtyField(uid, comp, nameof(MobCollisionComponent.BufferAccumulator));
|
||||
var direction = comp.Direction;
|
||||
|
||||
if (comp.BufferAccumulator <= 0f)
|
||||
{
|
||||
SetColliding((uid, comp), false, 1f);
|
||||
}
|
||||
// Apply the mob collision; if it's too low ignore it (e.g. if mob friction would overcome it).
|
||||
// This is so we don't spam velocity changes every tick. It's not that expensive for physics but
|
||||
// avoids the networking side.
|
||||
else if (direction != Vector2.Zero && PhysicsQuery.TryComp(uid, out var physics))
|
||||
{
|
||||
DebugTools.Assert(direction.LengthSquared() >= _minimumPushSquared);
|
||||
|
||||
if (direction.Length() > _pushingCap)
|
||||
{
|
||||
direction = direction.Normalized() * _pushingCap;
|
||||
}
|
||||
|
||||
Physics.ApplyLinearImpulse(uid, direction * physics.Mass, body: physics);
|
||||
comp.Direction = Vector2.Zero;
|
||||
DirtyField(uid, comp, nameof(MobCollisionComponent.Direction));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnMoveModifier(Entity<MobCollisionComponent> ent, ref RefreshMovementSpeedModifiersEvent args)
|
||||
{
|
||||
if (!ent.Comp.Colliding)
|
||||
return;
|
||||
|
||||
args.ModifySpeed(ent.Comp.SpeedModifier);
|
||||
}
|
||||
|
||||
private void SetColliding(Entity<MobCollisionComponent> entity, bool value, float speedMod)
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
entity.Comp.BufferAccumulator = BufferTime;
|
||||
DirtyField(entity.Owner, entity.Comp, nameof(MobCollisionComponent.BufferAccumulator));
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugTools.Assert(speedMod.Equals(1f));
|
||||
}
|
||||
|
||||
if (entity.Comp.Colliding != value)
|
||||
{
|
||||
entity.Comp.Colliding = value;
|
||||
DirtyField(entity.Owner, entity.Comp, nameof(MobCollisionComponent.Colliding));
|
||||
}
|
||||
|
||||
if (!entity.Comp.SpeedModifier.Equals(speedMod))
|
||||
{
|
||||
entity.Comp.SpeedModifier = speedMod;
|
||||
_moveMod.RefreshMovementSpeedModifiers(entity.Owner);
|
||||
DirtyField(entity.Owner, entity.Comp, nameof(MobCollisionComponent.SpeedModifier));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCollision(MobCollisionMessage msg, EntitySessionEventArgs args)
|
||||
{
|
||||
var player = args.SenderSession.AttachedEntity;
|
||||
|
||||
if (!MobQuery.TryComp(player, out var comp))
|
||||
return;
|
||||
|
||||
var xform = Transform(player.Value);
|
||||
|
||||
// If not parented directly to a grid then fail it.
|
||||
if (xform.ParentUid != xform.GridUid && xform.ParentUid != xform.MapUid)
|
||||
return;
|
||||
|
||||
var direction = msg.Direction;
|
||||
|
||||
MoveMob((player.Value, comp, xform), direction, msg.SpeedModifier);
|
||||
}
|
||||
|
||||
protected void MoveMob(Entity<MobCollisionComponent, TransformComponent> entity, Vector2 direction, float speedMod)
|
||||
{
|
||||
// Length too short to do anything.
|
||||
var pushing = true;
|
||||
|
||||
if (direction.LengthSquared() < _minimumPushSquared)
|
||||
{
|
||||
pushing = false;
|
||||
direction = Vector2.Zero;
|
||||
speedMod = 1f;
|
||||
}
|
||||
else if (float.IsNaN(direction.X) || float.IsNaN(direction.Y))
|
||||
{
|
||||
direction = Vector2.Zero;
|
||||
}
|
||||
|
||||
speedMod = Math.Clamp(speedMod, 0f, 1f);
|
||||
|
||||
SetColliding(entity, pushing, speedMod);
|
||||
|
||||
if (direction == entity.Comp1.Direction)
|
||||
return;
|
||||
|
||||
entity.Comp1.Direction = direction;
|
||||
DirtyField(entity.Owner, entity.Comp1, nameof(MobCollisionComponent.Direction));
|
||||
}
|
||||
|
||||
protected bool HandleCollisions(Entity<MobCollisionComponent, PhysicsComponent> entity, float frameTime)
|
||||
{
|
||||
var physics = entity.Comp2;
|
||||
|
||||
if (physics.ContactCount == 0)
|
||||
return false;
|
||||
|
||||
var ourVelocity = entity.Comp2.LinearVelocity;
|
||||
|
||||
if (ourVelocity == Vector2.Zero && !CfgManager.GetCVar(CCVars.MovementPushingStatic))
|
||||
return false;
|
||||
|
||||
var xform = Transform(entity.Owner);
|
||||
|
||||
if (xform.ParentUid != xform.GridUid && xform.ParentUid != xform.MapUid)
|
||||
return false;
|
||||
|
||||
var ev = new AttemptMobCollideEvent();
|
||||
|
||||
RaiseLocalEvent(entity.Owner, ref ev);
|
||||
|
||||
if (ev.Cancelled)
|
||||
return false;
|
||||
|
||||
var (worldPos, worldRot) = _xformSystem.GetWorldPositionRotation(xform);
|
||||
var ourTransform = new Transform(worldPos, worldRot);
|
||||
var contacts = Physics.GetContacts(entity.Owner);
|
||||
var direction = Vector2.Zero;
|
||||
var contactCount = 0;
|
||||
var ourMass = physics.FixturesMass;
|
||||
var speedMod = 1f;
|
||||
|
||||
while (contacts.MoveNext(out var contact))
|
||||
{
|
||||
if (!contact.IsTouching)
|
||||
continue;
|
||||
|
||||
var ourFixture = contact.OurFixture(entity.Owner);
|
||||
|
||||
if (ourFixture.Id != entity.Comp1.FixtureId)
|
||||
continue;
|
||||
|
||||
var other = contact.OtherEnt(entity.Owner);
|
||||
|
||||
if (!MobQuery.TryComp(other, out var otherComp) || !PhysicsQuery.TryComp(other, out var otherPhysics))
|
||||
continue;
|
||||
|
||||
var velocityProduct = Vector2.Dot(ourVelocity, otherPhysics.LinearVelocity);
|
||||
|
||||
// If we're moving opposite directions for example then ignore (based on cvar).
|
||||
if (velocityProduct < _pushingDotProduct)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var targetEv = new AttemptMobTargetCollideEvent();
|
||||
RaiseLocalEvent(other, ref targetEv);
|
||||
|
||||
if (targetEv.Cancelled)
|
||||
continue;
|
||||
|
||||
// TODO: More robust overlap detection.
|
||||
var otherTransform = Physics.GetPhysicsTransform(other);
|
||||
var diff = ourTransform.Position - otherTransform.Position;
|
||||
|
||||
if (diff == Vector2.Zero)
|
||||
{
|
||||
diff = _random.NextVector2(0.01f);
|
||||
}
|
||||
|
||||
// 0.7 for 0.35 + 0.35 for mob bounds (see TODO above).
|
||||
// Clamp so we don't get a heap of penetration depth and suddenly lurch other mobs.
|
||||
// This is also so we don't have to trigger the speed-cap above.
|
||||
// Maybe we just do speedcap and dump this? Though it's less configurable and the cap is just there for cheaters.
|
||||
var penDepth = Math.Clamp(0.7f - diff.Length(), 0f, _penCap);
|
||||
|
||||
// Sum the strengths so we get pushes back the same amount (impulse-wise, ignoring prediction).
|
||||
var mobMovement = penDepth * diff.Normalized() * (entity.Comp1.Strength + otherComp.Strength);
|
||||
|
||||
// Big mob push smaller mob, needs fine-tuning and potentially another co-efficient.
|
||||
if (_massDiffCap > 0f)
|
||||
{
|
||||
var modifier = Math.Clamp(
|
||||
otherPhysics.FixturesMass / ourMass,
|
||||
1f / _massDiffCap,
|
||||
_massDiffCap);
|
||||
|
||||
mobMovement *= modifier;
|
||||
|
||||
var speedReduction = 1f - entity.Comp1.MinimumSpeedModifier;
|
||||
var speedModifier = Math.Clamp(
|
||||
1f - speedReduction * modifier,
|
||||
entity.Comp1.MinimumSpeedModifier, 1f);
|
||||
|
||||
speedMod = MathF.Min(speedModifier, 1f);
|
||||
}
|
||||
|
||||
// Need the push strength proportional to penetration depth.
|
||||
direction += mobMovement;
|
||||
contactCount++;
|
||||
}
|
||||
|
||||
if (direction == Vector2.Zero)
|
||||
{
|
||||
return contactCount > 0;
|
||||
}
|
||||
|
||||
direction *= frameTime;
|
||||
RaiseCollisionEvent(entity.Owner, direction, speedMod);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected abstract void RaiseCollisionEvent(EntityUid uid, Vector2 direction, float speedmodifier);
|
||||
|
||||
/// <summary>
|
||||
/// Raised from client -> server indicating mob push direction OR server -> server for NPC mob pushes.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
protected sealed class MobCollisionMessage : EntityEventArgs
|
||||
{
|
||||
public Vector2 Direction;
|
||||
public float SpeedModifier;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised on the entity itself when attempting to handle mob collisions.
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public record struct AttemptMobCollideEvent
|
||||
{
|
||||
public bool Cancelled;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised on the other entity when attempting mob collisions.
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public record struct AttemptMobTargetCollideEvent
|
||||
{
|
||||
public bool Cancelled;
|
||||
}
|
||||
@@ -14,12 +14,12 @@ public abstract partial class SharedMoverController
|
||||
|
||||
private void OnAfterRelayTargetState(Entity<MovementRelayTargetComponent> entity, ref AfterAutoHandleStateEvent args)
|
||||
{
|
||||
Physics.UpdateIsPredicted(entity.Owner);
|
||||
PhysicsSystem.UpdateIsPredicted(entity.Owner);
|
||||
}
|
||||
|
||||
private void OnAfterRelayState(Entity<RelayInputMoverComponent> entity, ref AfterAutoHandleStateEvent args)
|
||||
{
|
||||
Physics.UpdateIsPredicted(entity.Owner);
|
||||
PhysicsSystem.UpdateIsPredicted(entity.Owner);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -42,7 +42,7 @@ public abstract partial class SharedMoverController
|
||||
{
|
||||
oldTarget.Source = EntityUid.Invalid;
|
||||
RemComp(component.RelayEntity, oldTarget);
|
||||
Physics.UpdateIsPredicted(component.RelayEntity);
|
||||
PhysicsSystem.UpdateIsPredicted(component.RelayEntity);
|
||||
}
|
||||
|
||||
var targetComp = EnsureComp<MovementRelayTargetComponent>(relayEntity);
|
||||
@@ -50,11 +50,11 @@ public abstract partial class SharedMoverController
|
||||
{
|
||||
oldRelay.RelayEntity = EntityUid.Invalid;
|
||||
RemComp(targetComp.Source, oldRelay);
|
||||
Physics.UpdateIsPredicted(targetComp.Source);
|
||||
PhysicsSystem.UpdateIsPredicted(targetComp.Source);
|
||||
}
|
||||
|
||||
Physics.UpdateIsPredicted(uid);
|
||||
Physics.UpdateIsPredicted(relayEntity);
|
||||
PhysicsSystem.UpdateIsPredicted(uid);
|
||||
PhysicsSystem.UpdateIsPredicted(relayEntity);
|
||||
component.RelayEntity = relayEntity;
|
||||
targetComp.Source = uid;
|
||||
Dirty(uid, component);
|
||||
@@ -63,8 +63,8 @@ public abstract partial class SharedMoverController
|
||||
|
||||
private void OnRelayShutdown(Entity<RelayInputMoverComponent> entity, ref ComponentShutdown args)
|
||||
{
|
||||
Physics.UpdateIsPredicted(entity.Owner);
|
||||
Physics.UpdateIsPredicted(entity.Comp.RelayEntity);
|
||||
PhysicsSystem.UpdateIsPredicted(entity.Owner);
|
||||
PhysicsSystem.UpdateIsPredicted(entity.Comp.RelayEntity);
|
||||
|
||||
if (TryComp<InputMoverComponent>(entity.Comp.RelayEntity, out var inputMover))
|
||||
SetMoveInput((entity.Comp.RelayEntity, inputMover), MoveButtons.None);
|
||||
@@ -78,8 +78,8 @@ public abstract partial class SharedMoverController
|
||||
|
||||
private void OnTargetRelayShutdown(Entity<MovementRelayTargetComponent> entity, ref ComponentShutdown args)
|
||||
{
|
||||
Physics.UpdateIsPredicted(entity.Owner);
|
||||
Physics.UpdateIsPredicted(entity.Comp.Source);
|
||||
PhysicsSystem.UpdateIsPredicted(entity.Owner);
|
||||
PhysicsSystem.UpdateIsPredicted(entity.Comp.Source);
|
||||
|
||||
if (Timing.ApplyingState)
|
||||
return;
|
||||
|
||||
@@ -20,6 +20,7 @@ using Robust.Shared.Physics;
|
||||
using Robust.Shared.Physics.Components;
|
||||
using Robust.Shared.Physics.Controllers;
|
||||
using Robust.Shared.Physics.Systems;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
using PullableComponent = Content.Shared.Movement.Pulling.Components.PullableComponent;
|
||||
@@ -43,7 +44,6 @@ public abstract partial class SharedMoverController : VirtualController
|
||||
[Dependency] private readonly SharedContainerSystem _container = default!;
|
||||
[Dependency] private readonly SharedMapSystem _mapSystem = default!;
|
||||
[Dependency] private readonly SharedGravitySystem _gravity = default!;
|
||||
[Dependency] protected readonly SharedPhysicsSystem Physics = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly TagSystem _tags = default!;
|
||||
|
||||
@@ -60,6 +60,8 @@ public abstract partial class SharedMoverController : VirtualController
|
||||
protected EntityQuery<FootstepModifierComponent> FootstepModifierQuery;
|
||||
protected EntityQuery<MapGridComponent> MapGridQuery;
|
||||
|
||||
private static readonly ProtoId<TagPrototype> FootstepSoundTag = "FootstepSound";
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="CCVars.StopSpeed"/>
|
||||
/// </summary>
|
||||
@@ -105,6 +107,14 @@ public abstract partial class SharedMoverController : VirtualController
|
||||
public override void UpdateAfterSolve(bool prediction, float frameTime)
|
||||
{
|
||||
base.UpdateAfterSolve(prediction, frameTime);
|
||||
|
||||
var query = AllEntityQuery<InputMoverComponent, PhysicsComponent>();
|
||||
|
||||
while (query.MoveNext(out var uid, out var _, out var physics))
|
||||
{
|
||||
//PhysicsSystem.SetLinearVelocity(uid, Vector2.Zero, body: physics);
|
||||
}
|
||||
|
||||
UsedMobMovement.Clear();
|
||||
}
|
||||
|
||||
@@ -424,7 +434,7 @@ public abstract partial class SharedMoverController : VirtualController
|
||||
{
|
||||
sound = null;
|
||||
|
||||
if (!CanSound() || !_tags.HasTag(uid, "FootstepSound"))
|
||||
if (!CanSound() || !_tags.HasTag(uid, FootstepSoundTag))
|
||||
return false;
|
||||
|
||||
var coordinates = xform.Coordinates;
|
||||
|
||||
@@ -9,6 +9,7 @@ using Content.Shared.Tag;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using static Content.Shared.Paper.PaperComponent;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared.Paper;
|
||||
|
||||
@@ -23,6 +24,9 @@ public sealed class PaperSystem : EntitySystem
|
||||
[Dependency] private readonly MetaDataSystem _metaSystem = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
|
||||
private static readonly ProtoId<TagPrototype> WriteIgnoreStampsTag = "WriteIgnoreStamps";
|
||||
private static readonly ProtoId<TagPrototype> WriteTag = "Write";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -100,8 +104,8 @@ public sealed class PaperSystem : EntitySystem
|
||||
private void OnInteractUsing(Entity<PaperComponent> entity, ref InteractUsingEvent args)
|
||||
{
|
||||
// only allow editing if there are no stamps or when using a cyberpen
|
||||
var editable = entity.Comp.StampedBy.Count == 0 || _tagSystem.HasTag(args.Used, "WriteIgnoreStamps");
|
||||
if (_tagSystem.HasTag(args.Used, "Write"))
|
||||
var editable = entity.Comp.StampedBy.Count == 0 || _tagSystem.HasTag(args.Used, WriteIgnoreStampsTag);
|
||||
if (_tagSystem.HasTag(args.Used, WriteTag))
|
||||
{
|
||||
if (editable)
|
||||
{
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System.Numerics;
|
||||
using Content.Shared.Conveyor;
|
||||
using Content.Shared.Gravity;
|
||||
using Content.Shared.Magic;
|
||||
using Content.Shared.Movement.Components;
|
||||
using Content.Shared.Movement.Events;
|
||||
using Content.Shared.Movement.Systems;
|
||||
|
||||
@@ -66,8 +66,7 @@ public abstract partial class SharedProjectileSystem : EntitySystem
|
||||
|
||||
private void OnEmbedRemove(Entity<EmbeddableProjectileComponent> embeddable, ref RemoveEmbeddedProjectileEvent args)
|
||||
{
|
||||
// Whacky prediction issues.
|
||||
if (args.Cancelled || _net.IsClient)
|
||||
if (args.Cancelled)
|
||||
return;
|
||||
|
||||
EmbedDetach(embeddable, embeddable.Comp, args.User);
|
||||
|
||||
@@ -51,6 +51,7 @@ public class RCDSystem : EntitySystem
|
||||
private readonly EntProtoId _instantConstructionFx = "EffectRCDConstruct0";
|
||||
private readonly ProtoId<RCDPrototype> _deconstructTileProto = "DeconstructTile";
|
||||
private readonly ProtoId<RCDPrototype> _deconstructLatticeProto = "DeconstructLattice";
|
||||
private static readonly ProtoId<TagPrototype> CatwalkTag = "Catwalk";
|
||||
|
||||
private HashSet<EntityUid> _intersectingEntities = new();
|
||||
|
||||
@@ -411,7 +412,7 @@ public class RCDSystem : EntitySystem
|
||||
if (isWindow && HasComp<SharedCanBuildWindowOnTopComponent>(ent))
|
||||
continue;
|
||||
|
||||
if (isCatwalk && _tags.HasTag(ent, "Catwalk"))
|
||||
if (isCatwalk && _tags.HasTag(ent, CatwalkTag))
|
||||
{
|
||||
if (popMsgs)
|
||||
_popup.PopupClient(Loc.GetString("rcd-component-cannot-build-on-occupied-tile-message"), uid, user);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Movement.Systems;
|
||||
using Content.Shared.Physics;
|
||||
using Content.Shared.Rotation;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
@@ -16,6 +17,29 @@ public sealed class StandingStateSystem : EntitySystem
|
||||
// If StandingCollisionLayer value is ever changed to more than one layer, the logic needs to be edited.
|
||||
private const int StandingCollisionLayer = (int) CollisionGroup.MidImpassable;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<StandingStateComponent, AttemptMobCollideEvent>(OnMobCollide);
|
||||
SubscribeLocalEvent<StandingStateComponent, AttemptMobTargetCollideEvent>(OnMobTargetCollide);
|
||||
}
|
||||
|
||||
private void OnMobTargetCollide(Entity<StandingStateComponent> ent, ref AttemptMobTargetCollideEvent args)
|
||||
{
|
||||
if (!ent.Comp.Standing)
|
||||
{
|
||||
args.Cancelled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnMobCollide(Entity<StandingStateComponent> ent, ref AttemptMobCollideEvent args)
|
||||
{
|
||||
if (!ent.Comp.Standing)
|
||||
{
|
||||
args.Cancelled = true;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsDown(EntityUid uid, StandingStateComponent? standingState = null)
|
||||
{
|
||||
if (!Resolve(uid, ref standingState, false))
|
||||
|
||||
@@ -1,103 +1,4 @@
|
||||
Entries:
|
||||
- author: ArZarLordOfMango
|
||||
changes:
|
||||
- message: Most toggleable clothing must now be equipped to toggle their actions.
|
||||
type: Fix
|
||||
id: 7623
|
||||
time: '2024-11-19T20:31:38.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/32826
|
||||
- author: Plykiya
|
||||
changes:
|
||||
- message: The SWAT crate from cargo now requires armory access to open.
|
||||
type: Fix
|
||||
id: 7624
|
||||
time: '2024-11-20T00:57:01.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/33415
|
||||
- author: SlamBamActionman
|
||||
changes:
|
||||
- message: It's no longer possible to drag an item out of a container's UI to drop
|
||||
it.
|
||||
type: Tweak
|
||||
id: 7625
|
||||
time: '2024-11-20T01:00:38.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/32706
|
||||
- author: Plykiya
|
||||
changes:
|
||||
- message: The crew monitoring crate now contains a flatpack of the server and computers,
|
||||
and can be opened with science access instead of engineering access now.
|
||||
type: Tweak
|
||||
id: 7626
|
||||
time: '2024-11-20T01:05:20.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/33417
|
||||
- author: Beck Thompson
|
||||
changes:
|
||||
- message: Toggle verbs are no longer duplicated on magboots and fire extinguishers!
|
||||
type: Fix
|
||||
id: 7627
|
||||
time: '2024-11-20T01:53:53.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/32138
|
||||
- author: qwerltaz
|
||||
changes:
|
||||
- message: A new grid item view is available in the construction menu, togglable
|
||||
with a button.
|
||||
type: Add
|
||||
- message: Construction menu default window size was tweaked.
|
||||
type: Tweak
|
||||
id: 7628
|
||||
time: '2024-11-20T01:54:49.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/32577
|
||||
- author: SpaceLizard24
|
||||
changes:
|
||||
- message: Reduced crafting costs of colored light tubes.
|
||||
type: Tweak
|
||||
id: 7629
|
||||
time: '2024-11-20T01:59:31.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/33376
|
||||
- author: thetolbean
|
||||
changes:
|
||||
- message: Items with a damage of 0 now have correct damage examination text.
|
||||
type: Fix
|
||||
id: 7630
|
||||
time: '2024-11-20T02:05:15.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/33064
|
||||
- author: SaphireLattice
|
||||
changes:
|
||||
- message: The Singularity/Tesla generator now requires being surrounded by containment
|
||||
fields to activate. This can be disabled with an Emag.
|
||||
type: Tweak
|
||||
id: 7631
|
||||
time: '2024-11-20T05:55:58.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/33358
|
||||
- author: TheWaffleJesus
|
||||
changes:
|
||||
- message: You can now craft items with stacks of capacitors without it eating it
|
||||
all!
|
||||
type: Fix
|
||||
id: 7632
|
||||
time: '2024-11-20T07:18:38.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/31966
|
||||
- author: ScarKy0, GoldenCan
|
||||
changes:
|
||||
- message: Ion stormed lawsets no longer persist between shifts.
|
||||
type: Fix
|
||||
- message: Cyborgs are now notified when inserted into a chassis with modified laws.
|
||||
type: Tweak
|
||||
id: 7633
|
||||
time: '2024-11-20T07:55:12.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/33311
|
||||
- author: ScarKy0, GoldenCan
|
||||
changes:
|
||||
- message: The Derelict Cyborg - a broken cyborg with altered laws due to year of
|
||||
exposure to ion storms - can now appear as a ghost role through a new midround
|
||||
event.
|
||||
type: Add
|
||||
- message: An ion storm affecting a Cyborg can no longer alter the law order of
|
||||
the AI, cyborgs created later in the round or AI's and cyborgs in subsequent
|
||||
rounds.
|
||||
type: Fix
|
||||
id: 7634
|
||||
time: '2024-11-20T07:55:13.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/32499
|
||||
- author: IProduceWidgets
|
||||
changes:
|
||||
- message: Presents no longer make non-items into items
|
||||
@@ -3900,3 +3801,90 @@
|
||||
id: 8122
|
||||
time: '2025-04-01T23:26:53.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/35191
|
||||
- author: Fildrance
|
||||
changes:
|
||||
- message: fixed missing deconstruct on RCD
|
||||
type: Fix
|
||||
id: 8123
|
||||
time: '2025-04-02T16:11:35.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/36255
|
||||
- author: qwerltaz
|
||||
changes:
|
||||
- message: Dragon rifts now shine a different color depending on charge progress.
|
||||
type: Add
|
||||
id: 8124
|
||||
time: '2025-04-02T18:37:35.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/36216
|
||||
- author: aada
|
||||
changes:
|
||||
- message: Diphenhydramine now causes light drowsiness.
|
||||
type: Tweak
|
||||
id: 8125
|
||||
time: '2025-04-03T06:29:52.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/36212
|
||||
- author: sowelipililimute
|
||||
changes:
|
||||
- message: You can now more easily interact with objects behind faded ones, and
|
||||
you can look behind fadeable objects in your FOV by hovering them with your
|
||||
mouse pointer
|
||||
type: Add
|
||||
id: 8126
|
||||
time: '2025-04-03T06:58:05.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/35863
|
||||
- author: whatston3
|
||||
changes:
|
||||
- message: Fancy tables and curtains now respect carpet stacks.
|
||||
type: Fix
|
||||
id: 8127
|
||||
time: '2025-04-03T14:45:04.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/33721
|
||||
- author: YuNii
|
||||
changes:
|
||||
- message: Stop ghosts from being logged to airlocks
|
||||
type: Fix
|
||||
id: 8128
|
||||
time: '2025-04-03T22:24:30.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/36261
|
||||
- author: K-Dynamic
|
||||
changes:
|
||||
- message: Proto-Kinetic Accelerators and PTK-800 Shuttle Gun recipes are now available
|
||||
to the security techfab when researched by science.
|
||||
type: Add
|
||||
id: 8129
|
||||
time: '2025-04-04T13:12:04.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/34566
|
||||
- author: lzk228
|
||||
changes:
|
||||
- message: Fix ability to use implants on borgs and bots.
|
||||
type: Fix
|
||||
id: 8130
|
||||
time: '2025-04-04T15:36:28.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/36218
|
||||
- author: TheBlueYowie
|
||||
changes:
|
||||
- message: Aligned Adv. Mineral Scanner rotation in inventory
|
||||
type: Tweak
|
||||
id: 8131
|
||||
time: '2025-04-04T15:56:30.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/36294
|
||||
- author: Tayrtahn
|
||||
changes:
|
||||
- message: Fixed ninjas being unable to hack criminal records consoles.
|
||||
type: Fix
|
||||
id: 8132
|
||||
time: '2025-04-04T17:46:59.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/36299
|
||||
- author: ScarKy0
|
||||
changes:
|
||||
- message: Players now require 1h of playtime before selecting any antagonist role.
|
||||
type: Tweak
|
||||
id: 8133
|
||||
time: '2025-04-04T20:24:05.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/36276
|
||||
- author: aada
|
||||
changes:
|
||||
- message: SyndieJuice now comes with 10 units of liquid plasma.
|
||||
type: Add
|
||||
id: 8134
|
||||
time: '2025-04-05T03:22:12.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/36280
|
||||
|
||||
@@ -15,6 +15,9 @@ quick_lottery = true
|
||||
[gateway]
|
||||
generator_enabled = false
|
||||
|
||||
[movement]
|
||||
mob_pushing = true
|
||||
|
||||
[physics]
|
||||
# Makes mapping annoying
|
||||
grid_splitting = false
|
||||
|
||||
@@ -31,6 +31,9 @@ appeal = "https://appeal.ss14.io"
|
||||
[server]
|
||||
rules_file = "StandardRuleset"
|
||||
|
||||
[movement]
|
||||
mob_pushing = true
|
||||
|
||||
[net]
|
||||
max_connections = 1024
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
agent-id-no-new = Didn't gain any new accesses from {THE($card)}.
|
||||
agent-id-new-1 = Gained one new access from {THE($card)}.
|
||||
agent-id-new = Gained {$number} new accesses from {THE($card)}.
|
||||
agent-id-new = { $number ->
|
||||
[0] Didn't gain any new accesses from {THE($card)}.
|
||||
[one] Gained one new access from {THE($card)}.
|
||||
*[other] Gained {$number} new accesses from {THE($card)}.
|
||||
}
|
||||
|
||||
agent-id-card-current-name = Name:
|
||||
agent-id-card-current-job = Job:
|
||||
agent-id-card-job-icon-label = Job icon:
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
admin-alert-shared-connection = {$player} is sharing a connection with {$otherCount} connected player(s): {$otherList}
|
||||
admin-alert-ipintel-blocked = {$player} was rejected from joining due to their IP having a {TOSTRING($percent, "P0")} confidence of being a VPN/Datacenter.
|
||||
admin-alert-ipintel-warning = {$player} IP has a {TOSTRING($percent, "P0")} confidence of being a VPN/Datacenter. Please watch them.
|
||||
admin-alert-ipintel-blocked = {$player} was rejected from joining due to their IP having a {TOSTRING($percent, "P2")} confidence of being a VPN/Datacenter.
|
||||
admin-alert-ipintel-warning = {$player} IP has a {TOSTRING($percent, "P2")} confidence of being a VPN/Datacenter. Please watch them.
|
||||
|
||||
@@ -15,12 +15,21 @@ air-alarm-ui-window-resync-devices-label = Resync
|
||||
air-alarm-ui-window-mode-label = Mode
|
||||
air-alarm-ui-window-auto-mode-label = Auto mode
|
||||
|
||||
-air-alarm-state-name = { $state ->
|
||||
[normal] Normal
|
||||
[warning] Warning
|
||||
[danger] Danger
|
||||
[emagged] Emagged
|
||||
*[invalid] Invalid
|
||||
}
|
||||
|
||||
air-alarm-ui-window-listing-title = {$address} : {-air-alarm-state-name(state:$state)}
|
||||
air-alarm-ui-window-pressure = {$pressure} kPa
|
||||
air-alarm-ui-window-pressure-indicator = Pressure: [color={$color}]{$pressure} kPa[/color]
|
||||
air-alarm-ui-window-temperature = {$tempC} C ({$temperature} K)
|
||||
air-alarm-ui-window-temperature-indicator = Temperature: [color={$color}]{$tempC} C ({$temperature} K)[/color]
|
||||
air-alarm-ui-window-alarm-state = [color={$color}]{$state}[/color]
|
||||
air-alarm-ui-window-alarm-state-indicator = Status: [color={$color}]{$state}[/color]
|
||||
air-alarm-ui-window-alarm-state = [color={$color}]{-air-alarm-state-name(state:$state)}[/color]
|
||||
air-alarm-ui-window-alarm-state-indicator = Status: [color={$color}]{-air-alarm-state-name(state:$state)}[/color]
|
||||
|
||||
air-alarm-ui-window-tab-vents = Vents
|
||||
air-alarm-ui-window-tab-scrubbers = Scrubbers
|
||||
|
||||
@@ -1 +1 @@
|
||||
bodyburn-text-others = {$name} burns to ash!
|
||||
bodyburn-text-others = {CAPITALIZE(THE($name))} burns to ash!
|
||||
|
||||
@@ -6,10 +6,10 @@ magic-mirror-remove-slot-self = You're removing some of your hair.
|
||||
magic-mirror-change-slot-self = You're changing your hairstyle.
|
||||
magic-mirror-change-color-self = You're changing your hair color.
|
||||
|
||||
magic-mirror-add-slot-target = Hair is being added to you by {$user}.
|
||||
magic-mirror-remove-slot-target = Your hair is being cut off by {$user}.
|
||||
magic-mirror-change-slot-target = Your hairstyle is being changed by {$user}.
|
||||
magic-mirror-change-color-target = Your hair color is being changed by {$user}.
|
||||
magic-mirror-add-slot-target = Hair is being added to you by {THE($user)}.
|
||||
magic-mirror-remove-slot-target = Your hair is being cut off by {THE($user)}.
|
||||
magic-mirror-change-slot-target = Your hairstyle is being changed by {THE($user)}.
|
||||
magic-mirror-change-color-target = Your hair color is being changed by {THE($user)}.
|
||||
|
||||
magic-mirror-blocked-by-hat-self = You need to take off your hat before changing your hair.
|
||||
magic-mirror-blocked-by-hat-self-target = You try to change their hair but their clothes gets in the way.
|
||||
magic-mirror-blocked-by-hat-self-target = You try to change {POSS-ADJ($target)} hair but {POSS-ADJ($target)} clothes get in the way.
|
||||
|
||||
@@ -3,7 +3,7 @@ suicide-command-help-text = The suicide command gives you a quick way out of a r
|
||||
The method varies, first it will attempt to use the held item in your active hand.
|
||||
If that fails, it will attempt to use an object in the environment.
|
||||
Finally, if neither of the above worked, you will die by biting your tongue.
|
||||
suicide-command-default-text-others = {$name} is attempting to bite their own tongue!
|
||||
suicide-command-default-text-others = {CAPITALIZE(THE($name))} is attempting to bite {POSS-ADJ($name)} own tongue!
|
||||
suicide-command-default-text-self = You attempt to bite your own tongue!
|
||||
suicide-command-already-dead = You can't suicide. You're dead.
|
||||
suicide-command-no-mind = You have no mind!
|
||||
|
||||
@@ -10,14 +10,14 @@ injector-volume-label = Volume: [color=white]{$currentVolume}/{$totalVolume}[/co
|
||||
|
||||
injector-component-drawing-text = Now drawing
|
||||
injector-component-injecting-text = Now injecting
|
||||
injector-component-cannot-transfer-message = You aren't able to transfer to {$target}!
|
||||
injector-component-cannot-draw-message = You aren't able to draw from {$target}!
|
||||
injector-component-cannot-inject-message = You aren't able to inject to {$target}!
|
||||
injector-component-inject-success-message = You inject {$amount}u into {$target}!
|
||||
injector-component-transfer-success-message = You transfer {$amount}u into {$target}.
|
||||
injector-component-draw-success-message = You draw {$amount}u from {$target}.
|
||||
injector-component-target-already-full-message = {$target} is already full!
|
||||
injector-component-target-is-empty-message = {$target} is empty!
|
||||
injector-component-cannot-transfer-message = You aren't able to transfer to {THE($target)}!
|
||||
injector-component-cannot-draw-message = You aren't able to draw from {THE($target)}!
|
||||
injector-component-cannot-inject-message = You aren't able to inject to {THE($target)}!
|
||||
injector-component-inject-success-message = You inject {$amount}u into {THE($target)}!
|
||||
injector-component-transfer-success-message = You transfer {$amount}u into {THE($target)}.
|
||||
injector-component-draw-success-message = You draw {$amount}u from {THE($target)}.
|
||||
injector-component-target-already-full-message = {CAPITALIZE(THE($target))} is already full!
|
||||
injector-component-target-is-empty-message = {CAPITALIZE(THE($target))} is empty!
|
||||
injector-component-cannot-toggle-draw-message = Too full to draw!
|
||||
injector-component-cannot-toggle-inject-message = Nothing to inject!
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ reagent-name-dylovene = dylovene
|
||||
reagent-desc-dylovene = A broad-spectrum anti-toxin, which treats toxin damage in organisms. Overdosing will cause vomiting, dizzyness and pain.
|
||||
|
||||
reagent-name-diphenhydramine = diphenhydramine
|
||||
reagent-desc-diphenhydramine = Rapidly purges the body of histamine, reduces jitteriness, and treats poison damage.
|
||||
reagent-desc-diphenhydramine = Rapidly purges the body of histamine, reduces jitteriness, causes drowsiness, and treats poison damage. Often included in sleep medication.
|
||||
|
||||
reagent-name-arithrazine = arithrazine
|
||||
reagent-desc-arithrazine = A mildly unstable medication used for the most extreme case of radiation poisoning. Exerts minor stress on the body.
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
JugSugar: 3
|
||||
JugSulfur: 1
|
||||
JugWeldingFuel: 1
|
||||
PlasmaChemistryVial: 1
|
||||
contrabandInventory:
|
||||
DrinkLithiumFlask: 1
|
||||
StrangePill: 3
|
||||
|
||||
@@ -187,12 +187,12 @@
|
||||
- HeadTop
|
||||
- HeadSide
|
||||
|
||||
#Templar Helmet
|
||||
#Knight Helmet
|
||||
- type: entity
|
||||
parent: ClothingHeadBase
|
||||
id: ClothingHeadHelmetTemplar
|
||||
name: templar helmet
|
||||
description: DEUS VULT!
|
||||
name: knight helmet
|
||||
description: Decorative helmet fashioned to resemble the knights of old.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Head/Helmets/templar.rsi
|
||||
|
||||
@@ -236,6 +236,7 @@
|
||||
- DoorBumpOpener
|
||||
- FootstepSound
|
||||
- CanPilot
|
||||
- Unimplantable
|
||||
- type: Emoting
|
||||
- type: GuideHelp
|
||||
guides:
|
||||
|
||||
@@ -66,6 +66,7 @@
|
||||
tags:
|
||||
- DoorBumpOpener
|
||||
- Bot
|
||||
- Unimplantable
|
||||
- type: MobState
|
||||
allowedStates:
|
||||
- Alive
|
||||
@@ -451,6 +452,7 @@
|
||||
- DoorBumpOpener
|
||||
- FootstepSound
|
||||
- Bot
|
||||
- Unimplantable
|
||||
- type: ActiveRadio
|
||||
channels:
|
||||
- Common
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
- BypassDropChecks
|
||||
- NoConsoleSound
|
||||
- SilentStorageUser
|
||||
- PreventAccessLogging
|
||||
- type: Input
|
||||
context: "aghost"
|
||||
- type: Ghost
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
- type: Sprite
|
||||
noRot: true
|
||||
drawdepth: Mobs
|
||||
- type: MobCollision
|
||||
- type: Physics
|
||||
bodyType: KinematicController
|
||||
- type: Fixtures
|
||||
|
||||
@@ -14,9 +14,6 @@
|
||||
- Plating
|
||||
- type: Stack
|
||||
stackType: FloorCarpetRed
|
||||
- type: Tag
|
||||
tags:
|
||||
- CarpetRed
|
||||
- type: SpawnAfterInteract #Nuke after convert to FloorTile
|
||||
prototype: Carpet
|
||||
doAfter: 0.5
|
||||
@@ -33,9 +30,6 @@
|
||||
heldPrefix: carpet-black
|
||||
- type: Stack
|
||||
stackType: FloorCarpetBlack
|
||||
- type: Tag
|
||||
tags:
|
||||
- CarpetBlack
|
||||
- type: SpawnAfterInteract #Nuke after convert to FloorTile
|
||||
prototype: CarpetBlack
|
||||
doAfter: 0.5
|
||||
@@ -52,9 +46,6 @@
|
||||
heldPrefix: carpet-blue
|
||||
- type: Stack
|
||||
stackType: FloorCarpetBlue
|
||||
- type: Tag
|
||||
tags:
|
||||
- CarpetBlue
|
||||
- type: SpawnAfterInteract #Nuke after convert to FloorTile
|
||||
prototype: CarpetBlue
|
||||
doAfter: 0.5
|
||||
@@ -71,9 +62,6 @@
|
||||
heldPrefix: carpet-green
|
||||
- type: Stack
|
||||
stackType: FloorCarpetGreen
|
||||
- type: Tag
|
||||
tags:
|
||||
- CarpetGreen
|
||||
- type: SpawnAfterInteract #Nuke after convert to FloorTile
|
||||
prototype: CarpetGreen
|
||||
doAfter: 0.5
|
||||
@@ -90,9 +78,6 @@
|
||||
heldPrefix: carpet-orange
|
||||
- type: Stack
|
||||
stackType: FloorCarpetOrange
|
||||
- type: Tag
|
||||
tags:
|
||||
- CarpetOrange
|
||||
- type: SpawnAfterInteract #Nuke after convert to FloorTile
|
||||
prototype: CarpetOrange
|
||||
doAfter: 0.5
|
||||
@@ -109,9 +94,6 @@
|
||||
heldPrefix: carpet-skyblue
|
||||
- type: Stack
|
||||
stackType: FloorCarpetSkyBlue
|
||||
- type: Tag
|
||||
tags:
|
||||
- CarpetSBlue
|
||||
- type: SpawnAfterInteract #Nuke after convert to FloorTile
|
||||
prototype: CarpetSBlue
|
||||
doAfter: 0.5
|
||||
@@ -128,9 +110,6 @@
|
||||
heldPrefix: carpet-purple
|
||||
- type: Stack
|
||||
stackType: FloorCarpetPurple
|
||||
- type: Tag
|
||||
tags:
|
||||
- CarpetPurple
|
||||
- type: SpawnAfterInteract #Nuke after convert to FloorTile
|
||||
prototype: CarpetPurple
|
||||
doAfter: 0.5
|
||||
@@ -147,9 +126,6 @@
|
||||
heldPrefix: carpet-pink
|
||||
- type: Stack
|
||||
stackType: FloorCarpetPink
|
||||
- type: Tag
|
||||
tags:
|
||||
- CarpetPink
|
||||
- type: SpawnAfterInteract #Nuke after convert to FloorTile
|
||||
prototype: CarpetPink
|
||||
doAfter: 0.5
|
||||
@@ -166,9 +142,6 @@
|
||||
heldPrefix: carpet-cyan
|
||||
- type: Stack
|
||||
stackType: FloorCarpetCyan
|
||||
- type: Tag
|
||||
tags:
|
||||
- CarpetCyan
|
||||
- type: SpawnAfterInteract #Nuke after convert to FloorTile
|
||||
prototype: CarpetCyan
|
||||
doAfter: 0.5
|
||||
@@ -185,9 +158,6 @@
|
||||
heldPrefix: carpet-white
|
||||
- type: Stack
|
||||
stackType: FloorCarpetWhite
|
||||
- type: Tag
|
||||
tags:
|
||||
- CarpetWhite
|
||||
- type: SpawnAfterInteract #Nuke after convert to FloorTile
|
||||
prototype: CarpetWhite
|
||||
doAfter: 0.5
|
||||
|
||||
@@ -67,6 +67,8 @@
|
||||
shader: unshaded
|
||||
visible: false
|
||||
map: ["enum.ToggleVisuals.Layer"]
|
||||
- type: Item
|
||||
storedRotation: -90
|
||||
- type: MiningScanner
|
||||
range: 10
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
parent: BaseItem
|
||||
name: light replacer
|
||||
id: LightReplacer
|
||||
description: An item which uses magnets to easily replace broken lights. Refill By adding more lights into the replacer.
|
||||
description: An item which uses magnets to easily replace broken lights. Refill by adding more lights into the replacer.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Objects/Specific/Janitorial/light_replacer.rsi
|
||||
|
||||
@@ -240,4 +240,4 @@
|
||||
layer:
|
||||
- HighImpassable
|
||||
- type: Transform
|
||||
noRot: true
|
||||
noRot: false
|
||||
|
||||
@@ -394,6 +394,8 @@
|
||||
- SecurityAmmoStatic
|
||||
- SecurityWeaponsStatic
|
||||
dynamicPacks:
|
||||
- SalvageSecurityBoards
|
||||
- SalvageSecurityWeapons
|
||||
- SecurityEquipment
|
||||
- SecurityBoards
|
||||
- SecurityExplosives
|
||||
|
||||
@@ -2,25 +2,25 @@
|
||||
- type: rcd
|
||||
id: Invalid # Hidden prototype - do not add to RCDs
|
||||
mode: Invalid
|
||||
|
||||
|
||||
- type: rcd
|
||||
id: Deconstruct
|
||||
name: rcd-component-deconstruct
|
||||
category: Main
|
||||
category: WallsAndFlooring
|
||||
sprite: /Textures/Interface/Radial/RCD/deconstruct.png
|
||||
mode: Deconstruct
|
||||
prototype: EffectRCDDeconstructPreview
|
||||
rotation: Camera
|
||||
|
||||
- type: rcd
|
||||
id: DeconstructLattice # Hidden prototype - do not add to RCDs
|
||||
id: DeconstructLattice # Hidden prototype - do not add to RCDs
|
||||
name: rcd-component-deconstruct
|
||||
mode: Deconstruct
|
||||
cost: 2
|
||||
delay: 0
|
||||
rotation: Camera
|
||||
fx: EffectRCDConstruct0
|
||||
|
||||
|
||||
- type: rcd
|
||||
id: DeconstructTile # Hidden prototype - do not add to RCDs
|
||||
name: rcd-component-deconstruct
|
||||
@@ -30,7 +30,7 @@
|
||||
rotation: Camera
|
||||
fx: EffectRCDDeconstruct4
|
||||
|
||||
# Flooring
|
||||
# Flooring
|
||||
- type: rcd
|
||||
id: Plating
|
||||
name: rcd-component-plating
|
||||
@@ -44,7 +44,7 @@
|
||||
rules:
|
||||
- CanBuildOnEmptyTile
|
||||
fx: EffectRCDConstruct1
|
||||
|
||||
|
||||
- type: rcd
|
||||
id: FloorSteel
|
||||
name: rcd-component-floor-steel
|
||||
@@ -80,7 +80,7 @@
|
||||
category: WallsAndFlooring
|
||||
sprite: /Textures/Interface/Radial/RCD/solid_wall.png
|
||||
mode: ConstructObject
|
||||
prototype: WallSolid
|
||||
prototype: WallSolid
|
||||
cost: 4
|
||||
delay: 2
|
||||
collisionMask: FullTileMask
|
||||
@@ -113,7 +113,7 @@
|
||||
- IsWindow
|
||||
rotation: Fixed
|
||||
fx: EffectRCDConstruct2
|
||||
|
||||
|
||||
- type: rcd
|
||||
id: WindowDirectional
|
||||
category: WindowsAndGrilles
|
||||
@@ -128,7 +128,7 @@
|
||||
- IsWindow
|
||||
rotation: User
|
||||
fx: EffectRCDConstruct1
|
||||
|
||||
|
||||
- type: rcd
|
||||
id: ReinforcedWindow
|
||||
category: WindowsAndGrilles
|
||||
@@ -142,7 +142,7 @@
|
||||
- IsWindow
|
||||
rotation: User
|
||||
fx: EffectRCDConstruct3
|
||||
|
||||
|
||||
- type: rcd
|
||||
id: WindowReinforcedDirectional
|
||||
category: WindowsAndGrilles
|
||||
@@ -170,7 +170,7 @@
|
||||
collisionMask: FullTileMask
|
||||
rotation: Camera
|
||||
fx: EffectRCDConstruct4
|
||||
|
||||
|
||||
- type: rcd
|
||||
id: AirlockGlass
|
||||
category: Airlocks
|
||||
@@ -182,7 +182,7 @@
|
||||
collisionMask: FullTileMask
|
||||
rotation: Camera
|
||||
fx: EffectRCDConstruct4
|
||||
|
||||
|
||||
- type: rcd
|
||||
id: Firelock
|
||||
category: Airlocks
|
||||
@@ -208,7 +208,7 @@
|
||||
collisionBounds: "-0.23,-0.49,0.23,-0.36"
|
||||
rotation: User
|
||||
fx: EffectRCDConstruct1
|
||||
|
||||
|
||||
- type: rcd
|
||||
id: BulbLight
|
||||
category: Lighting
|
||||
@@ -235,7 +235,7 @@
|
||||
- MustBuildOnSubfloor
|
||||
rotation: Fixed
|
||||
fx: EffectRCDConstruct0
|
||||
|
||||
|
||||
- type: rcd
|
||||
id: MVCable
|
||||
category: Electrical
|
||||
@@ -248,7 +248,7 @@
|
||||
- MustBuildOnSubfloor
|
||||
rotation: Fixed
|
||||
fx: EffectRCDConstruct0
|
||||
|
||||
|
||||
- type: rcd
|
||||
id: HVCable
|
||||
category: Electrical
|
||||
@@ -261,7 +261,7 @@
|
||||
- MustBuildOnSubfloor
|
||||
rotation: Fixed
|
||||
fx: EffectRCDConstruct0
|
||||
|
||||
|
||||
- type: rcd
|
||||
id: CableTerminal
|
||||
category: Electrical
|
||||
|
||||
@@ -83,6 +83,12 @@
|
||||
key: Jitter
|
||||
time: 3.0
|
||||
type: Remove
|
||||
- !type:GenericStatusEffect
|
||||
key: Drowsiness
|
||||
component: Drowsiness
|
||||
time: 1.5
|
||||
type: Add
|
||||
refresh: false
|
||||
- !type:HealthChange
|
||||
damage:
|
||||
types:
|
||||
|
||||
@@ -17,93 +17,66 @@
|
||||
completed:
|
||||
- !type:SnapToGrid { }
|
||||
steps:
|
||||
- tag: CarpetBlack
|
||||
- material: FloorCarpetBlack
|
||||
amount: 1
|
||||
doAfter: 1
|
||||
name: black carpet
|
||||
icon:
|
||||
sprite: Objects/Tiles/tile.rsi
|
||||
state: carpet-black
|
||||
- to: CurtainsBlue
|
||||
completed:
|
||||
- !type:SnapToGrid { }
|
||||
steps:
|
||||
- tag: CarpetBlue
|
||||
- material: FloorCarpetBlue
|
||||
amount: 1
|
||||
doAfter: 1
|
||||
name: blue carpet
|
||||
icon:
|
||||
sprite: Objects/Tiles/tile.rsi
|
||||
state: carpet-blue
|
||||
- to: CurtainsCyan
|
||||
completed:
|
||||
- !type:SnapToGrid { }
|
||||
steps:
|
||||
- tag: CarpetCyan
|
||||
- material: FloorCarpetCyan
|
||||
amount: 1
|
||||
doAfter: 1
|
||||
name: cyan carpet
|
||||
icon:
|
||||
sprite: Objects/Tiles/tile.rsi
|
||||
state: carpet-cyan
|
||||
- to: CurtainsGreen
|
||||
completed:
|
||||
- !type:SnapToGrid { }
|
||||
steps:
|
||||
- tag: CarpetGreen
|
||||
- material: FloorCarpetGreen
|
||||
amount: 1
|
||||
doAfter: 1
|
||||
name: green carpet
|
||||
icon:
|
||||
sprite: Objects/Tiles/tile.rsi
|
||||
state: carpet-green
|
||||
- to: CurtainsOrange
|
||||
completed:
|
||||
- !type:SnapToGrid { }
|
||||
steps:
|
||||
- tag: CarpetOrange
|
||||
- material: FloorCarpetOrange
|
||||
amount: 1
|
||||
doAfter: 1
|
||||
name: orange carpet
|
||||
icon:
|
||||
sprite: Objects/Tiles/tile.rsi
|
||||
state: carpet-orange
|
||||
- to: CurtainsPink
|
||||
completed:
|
||||
- !type:SnapToGrid { }
|
||||
steps:
|
||||
- tag: CarpetPink
|
||||
- material: FloorCarpetPink
|
||||
amount: 1
|
||||
doAfter: 1
|
||||
name: pink carpet
|
||||
icon:
|
||||
sprite: Objects/Tiles/tile.rsi
|
||||
state: carpet-pink
|
||||
- to: CurtainsPurple
|
||||
completed:
|
||||
- !type:SnapToGrid { }
|
||||
steps:
|
||||
- tag: CarpetPurple
|
||||
- material: FloorCarpetPurple
|
||||
amount: 1
|
||||
doAfter: 1
|
||||
name: purple carpet
|
||||
icon:
|
||||
sprite: Objects/Tiles/tile.rsi
|
||||
state: carpet-purple
|
||||
- to: CurtainsRed
|
||||
completed:
|
||||
- !type:SnapToGrid { }
|
||||
steps:
|
||||
- tag: CarpetRed
|
||||
- material: FloorCarpetRed
|
||||
amount: 1
|
||||
doAfter: 1
|
||||
name: red carpet
|
||||
icon:
|
||||
sprite: Objects/Tiles/tile.rsi
|
||||
state: carpet-red
|
||||
- to: CurtainsWhite
|
||||
completed:
|
||||
- !type:SnapToGrid { }
|
||||
steps:
|
||||
- tag: CarpetWhite
|
||||
- material: FloorCarpetWhite
|
||||
amount: 1
|
||||
doAfter: 1
|
||||
name: white carpet
|
||||
icon:
|
||||
sprite: Objects/Tiles/tile.rsi
|
||||
state: carpet-white
|
||||
|
||||
|
||||
- node: Curtains
|
||||
entity: HospitalCurtains
|
||||
edges:
|
||||
@@ -126,7 +99,7 @@
|
||||
steps:
|
||||
- tool: Cutting
|
||||
doAfter: 1
|
||||
|
||||
|
||||
- node: CurtainsBlack
|
||||
entity: CurtainsBlack
|
||||
edges:
|
||||
@@ -148,8 +121,8 @@
|
||||
amount: 1
|
||||
steps:
|
||||
- tool: Cutting
|
||||
doAfter: 1
|
||||
|
||||
doAfter: 1
|
||||
|
||||
- node: CurtainsBlue
|
||||
entity: CurtainsBlue
|
||||
edges:
|
||||
@@ -172,7 +145,7 @@
|
||||
steps:
|
||||
- tool: Cutting
|
||||
doAfter: 1
|
||||
|
||||
|
||||
- node: CurtainsCyan
|
||||
entity: CurtainsCyan
|
||||
edges:
|
||||
@@ -195,7 +168,7 @@
|
||||
steps:
|
||||
- tool: Cutting
|
||||
doAfter: 1
|
||||
|
||||
|
||||
- node: CurtainsGreen
|
||||
entity: CurtainsGreen
|
||||
edges:
|
||||
@@ -218,7 +191,7 @@
|
||||
steps:
|
||||
- tool: Cutting
|
||||
doAfter: 1
|
||||
|
||||
|
||||
- node: CurtainsOrange
|
||||
entity: CurtainsOrange
|
||||
edges:
|
||||
@@ -241,7 +214,7 @@
|
||||
steps:
|
||||
- tool: Cutting
|
||||
doAfter: 1
|
||||
|
||||
|
||||
- node: CurtainsPink
|
||||
entity: CurtainsPink
|
||||
edges:
|
||||
@@ -264,7 +237,7 @@
|
||||
steps:
|
||||
- tool: Cutting
|
||||
doAfter: 1
|
||||
|
||||
|
||||
- node: CurtainsPurple
|
||||
entity: CurtainsPurple
|
||||
edges:
|
||||
@@ -287,7 +260,7 @@
|
||||
steps:
|
||||
- tool: Cutting
|
||||
doAfter: 1
|
||||
|
||||
|
||||
- node: CurtainsRed
|
||||
entity: CurtainsRed
|
||||
edges:
|
||||
@@ -310,7 +283,7 @@
|
||||
steps:
|
||||
- tool: Cutting
|
||||
doAfter: 1
|
||||
|
||||
|
||||
- node: CurtainsWhite
|
||||
entity: CurtainsWhite
|
||||
edges:
|
||||
|
||||
@@ -218,75 +218,48 @@
|
||||
|
||||
- to: TableFancyBlack
|
||||
steps:
|
||||
- tag: CarpetBlack
|
||||
name: black carpet
|
||||
icon:
|
||||
sprite: Objects/Tiles/tile.rsi
|
||||
state: carpet-black
|
||||
- material: FloorCarpetBlack
|
||||
amount: 1
|
||||
|
||||
- to: TableFancyBlue
|
||||
steps:
|
||||
- tag: CarpetBlue
|
||||
name: blue carpet
|
||||
icon:
|
||||
sprite: Objects/Tiles/tile.rsi
|
||||
state: carpet-blue
|
||||
- material: FloorCarpetBlue
|
||||
amount: 1
|
||||
|
||||
- to: TableFancyCyan
|
||||
steps:
|
||||
- tag: CarpetCyan
|
||||
name: cyan carpet
|
||||
icon:
|
||||
sprite: Objects/Tiles/tile.rsi
|
||||
state: carpet-cyan
|
||||
- material: FloorCarpetCyan
|
||||
amount: 1
|
||||
|
||||
- to: TableFancyGreen
|
||||
steps:
|
||||
- tag: CarpetGreen
|
||||
name: green carpet
|
||||
icon:
|
||||
sprite: Objects/Tiles/tile.rsi
|
||||
state: carpet-green
|
||||
- material: FloorCarpetGreen
|
||||
amount: 1
|
||||
|
||||
- to: TableFancyOrange
|
||||
steps:
|
||||
- tag: CarpetOrange
|
||||
name: orange carpet
|
||||
icon:
|
||||
sprite: Objects/Tiles/tile.rsi
|
||||
state: carpet-orange
|
||||
- material: FloorCarpetOrange
|
||||
amount: 1
|
||||
|
||||
- to: TableFancyPurple
|
||||
steps:
|
||||
- tag: CarpetPurple
|
||||
name: purple carpet
|
||||
icon:
|
||||
sprite: Objects/Tiles/tile.rsi
|
||||
state: carpet-purple
|
||||
- material: FloorCarpetPurple
|
||||
amount: 1
|
||||
|
||||
- to: TableFancyPink
|
||||
steps:
|
||||
- tag: CarpetPink
|
||||
name: pink carpet
|
||||
icon:
|
||||
sprite: Objects/Tiles/tile.rsi
|
||||
state: carpet-pink
|
||||
- material: FloorCarpetPink
|
||||
amount: 1
|
||||
|
||||
- to: TableFancyRed
|
||||
steps:
|
||||
- tag: CarpetRed
|
||||
name: red carpet
|
||||
icon:
|
||||
sprite: Objects/Tiles/tile.rsi
|
||||
state: carpet-red
|
||||
- material: FloorCarpetRed
|
||||
amount: 1
|
||||
|
||||
- to: TableFancyWhite
|
||||
steps:
|
||||
- tag: CarpetWhite
|
||||
name: white carpet
|
||||
icon:
|
||||
sprite: Objects/Tiles/tile.rsi
|
||||
state: carpet-white
|
||||
- material: FloorCarpetWhite
|
||||
amount: 1
|
||||
|
||||
- node: TableCarpet
|
||||
entity: TableCarpet
|
||||
|
||||
@@ -49,3 +49,13 @@
|
||||
- HandHeldMassScanner
|
||||
- ClothingMaskWeldingGas
|
||||
- SignallerAdvanced
|
||||
|
||||
- type: latheRecipePack
|
||||
id: SalvageSecurityBoards
|
||||
recipes:
|
||||
- ShuttleGunKineticCircuitboard
|
||||
|
||||
- type: latheRecipePack
|
||||
id: SalvageSecurityWeapons
|
||||
recipes:
|
||||
- WeaponProtoKineticAccelerator
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
setPreference: true
|
||||
objective: roles-antag-rev-head-objective
|
||||
guides: [ Revolutionaries ]
|
||||
requirements:
|
||||
- !type:OverallPlaytimeRequirement
|
||||
time: 3600 # 1h
|
||||
|
||||
- type: antag
|
||||
id: Rev
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
setPreference: true
|
||||
objective: roles-antag-thief-objective
|
||||
guides: [ Thieves ]
|
||||
requirements:
|
||||
- !type:OverallPlaytimeRequirement
|
||||
time: 3600 # 1h
|
||||
|
||||
- type: startingGear
|
||||
id: ThiefGear
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
setPreference: true
|
||||
objective: roles-antag-syndicate-agent-objective
|
||||
guides: [ Traitors ]
|
||||
requirements:
|
||||
- !type:OverallPlaytimeRequirement
|
||||
time: 3600 # 1h
|
||||
|
||||
- type: antag
|
||||
id: TraitorSleeper
|
||||
@@ -13,6 +16,9 @@
|
||||
setPreference: true
|
||||
objective: roles-antag-syndicate-agent-sleeper-objective
|
||||
guides: [ Traitors ]
|
||||
requirements:
|
||||
- !type:OverallPlaytimeRequirement
|
||||
time: 3600 # 1h
|
||||
|
||||
# Syndicate Operative Outfit - Monkey
|
||||
- type: startingGear
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
setPreference: true
|
||||
objective: roles-antag-initial-infected-objective
|
||||
guides: [ Zombies ]
|
||||
requirements:
|
||||
- !type:OverallPlaytimeRequirement
|
||||
time: 3600 # 1h
|
||||
|
||||
- type: antag
|
||||
id: Zombie
|
||||
|
||||
@@ -222,36 +222,6 @@
|
||||
- type: Tag
|
||||
id: Carpet
|
||||
|
||||
- type: Tag
|
||||
id: CarpetBlack
|
||||
|
||||
- type: Tag
|
||||
id: CarpetBlue
|
||||
|
||||
- type: Tag
|
||||
id: CarpetCyan
|
||||
|
||||
- type: Tag
|
||||
id: CarpetGreen
|
||||
|
||||
- type: Tag
|
||||
id: CarpetOrange
|
||||
|
||||
- type: Tag
|
||||
id: CarpetPink
|
||||
|
||||
- type: Tag
|
||||
id: CarpetPurple
|
||||
|
||||
- type: Tag
|
||||
id: CarpetRed
|
||||
|
||||
- type: Tag
|
||||
id: CarpetSBlue
|
||||
|
||||
- type: Tag
|
||||
id: CarpetWhite
|
||||
|
||||
- type: Tag
|
||||
id: Carrot
|
||||
|
||||
@@ -1056,6 +1026,9 @@
|
||||
- type: Tag
|
||||
id: Powerdrill
|
||||
|
||||
- type: Tag
|
||||
id: PreventAccessLogging
|
||||
|
||||
- type: Tag
|
||||
id: PrisonUniform
|
||||
|
||||
@@ -1317,10 +1290,10 @@
|
||||
|
||||
- type: Tag
|
||||
id: Truncheon
|
||||
|
||||
|
||||
- type: Tag
|
||||
id: TurretCompatibleWeapon # Used in the construction of sentry turrets
|
||||
|
||||
|
||||
- type: Tag
|
||||
id: TurretControlElectronics # Used in the construction of sentry turret control panels
|
||||
|
||||
|
||||
Reference in New Issue
Block a user