diff --git a/Content.Client/_Scp/ComplexElevator/Visualizers/ElevatorButtonVisualizerSystem.cs b/Content.Client/_Scp/ComplexElevator/Visualizers/ElevatorButtonVisualizerSystem.cs new file mode 100644 index 00000000000..e8cf29c8771 --- /dev/null +++ b/Content.Client/_Scp/ComplexElevator/Visualizers/ElevatorButtonVisualizerSystem.cs @@ -0,0 +1,19 @@ +using Content.Shared._Scp.ComplexElevator; +using Robust.Client.GameObjects; + +namespace Content.Client._Scp.ComplexElevator.Visualizers; + +public sealed class ElevatorButtonVisualizerSystem : VisualizerSystem +{ + protected override void OnAppearanceChange(EntityUid uid, ElevatorButtonVisualsComponent comp, ref AppearanceChangeEvent args) + { + if (args.Sprite == null) + return; + + if (!AppearanceSystem.TryGetData(uid, ElevatorButtonVisuals.ButtonState, out var state, args.Component)) + return; + + if (comp.SpriteStateMap.TryGetValue(state, out var spriteState)) + SpriteSystem.LayerSetRsiState((uid, args.Sprite), ElevatorButtonLayers.Base, spriteState); + } +} \ No newline at end of file diff --git a/Content.Client/_Scp/ComplexElevator/Visualizers/ElevatorButtonVisualsComponent.cs b/Content.Client/_Scp/ComplexElevator/Visualizers/ElevatorButtonVisualsComponent.cs new file mode 100644 index 00000000000..4d37797d1b8 --- /dev/null +++ b/Content.Client/_Scp/ComplexElevator/Visualizers/ElevatorButtonVisualsComponent.cs @@ -0,0 +1,19 @@ +using Content.Shared._Scp.ComplexElevator; + +namespace Content.Client._Scp.ComplexElevator.Visualizers; + +[RegisterComponent] +public sealed partial class ElevatorButtonVisualsComponent : Component +{ + /// + /// A map of the sprite states used by this visualizer indexed by the button state they correspond to. + /// + [DataField("spriteStateMap")] + [ViewVariables(VVAccess.ReadOnly)] + public Dictionary SpriteStateMap = new() + { + [ElevatorButtonState.ElevatorHere] = "elevator_here", + [ElevatorButtonState.ElevatorMoving] = "elevator_moving", + [ElevatorButtonState.ElevatorElsewhere] = "elevator_elsewhere", + }; +} \ No newline at end of file diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs index 67f3a207794..43a91e07bcf 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs @@ -226,6 +226,19 @@ public float GetTileHeatCapacity(Entity? grid, Entity< { return GetHeatCapacity(GetTileMixture(grid, map, tile) ?? GasMixture.SpaceGas); } + // fire added + public void SetTileMixture(Entity? grid, Entity? map, Vector2i gridTile, GasMixture mixture) + { + if (grid is {} gridEnt + && Resolve(gridEnt, ref gridEnt.Comp1, false) + && gridEnt.Comp1.Tiles.TryGetValue(gridTile, out var tile)) + { + tile.Air = mixture; + AddActiveTile(gridEnt.Comp1, tile); + InvalidateVisuals((gridEnt.Owner, gridEnt.Comp2), gridTile); + } + } + // fire end public TileMixtureEnumerator GetAdjacentTileMixtures(Entity grid, Vector2i tile, bool includeBlocked = false, bool excite = false) { diff --git a/Content.Server/Construction/ConstructionSystem.Initial.cs b/Content.Server/Construction/ConstructionSystem.Initial.cs index c783eda7985..f0b440e12f0 100644 --- a/Content.Server/Construction/ConstructionSystem.Initial.cs +++ b/Content.Server/Construction/ConstructionSystem.Initial.cs @@ -2,6 +2,7 @@ using System.Linq; using System.Threading.Tasks; using Content.Server.Construction.Components; +using Content.Shared._Scp.Construction; using Content.Shared._Sunrise.UnbuildableGrid; using Content.Shared.ActionBlocker; using Content.Shared.Construction; @@ -18,6 +19,7 @@ using Content.Shared.Whitelist; using Robust.Shared.Containers; using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Player; using Robust.Shared.Timing; @@ -494,12 +496,25 @@ void Cleanup() var mapPos = _transformSystem.ToMapCoordinates(location); var predicate = GetPredicate(constructionPrototype.CanBuildInImpassable, mapPos); + // fire added + var gridUid = _transformSystem.GetGrid(location); + if (TryComp(gridUid, out var mapGrid)) + { + var anchored = _map.GetAnchoredEntities((gridUid.Value, mapGrid), mapPos); + if (anchored.Any(e => HasComp(e))) + { + _popup.PopupEntity(Loc.GetString("construction-system-construct-marker-block"), user, user); + Cleanup(); + return; + } + } + // fire end + if (!_interactionSystem.InRangeUnobstructed(user, mapPos, predicate: predicate)) { Cleanup(); return; } - if (pathFind == null) throw new InvalidDataException($"Can't find path from starting node to target node in construction! Recipe: {ev.PrototypeName}"); diff --git a/Content.Server/_Scp/ComplexElevator/ComplexElevatorComponent.cs b/Content.Server/_Scp/ComplexElevator/ComplexElevatorComponent.cs index 56c7adf0e6c..bb8e733f254 100644 --- a/Content.Server/_Scp/ComplexElevator/ComplexElevatorComponent.cs +++ b/Content.Server/_Scp/ComplexElevator/ComplexElevatorComponent.cs @@ -39,7 +39,19 @@ public sealed partial class ComplexElevatorComponent : Component public SoundSpecifier ArrivalSound = new SoundPathSpecifier("/Audio/_Scp/Machines/Elevator/Beep-elevator.ogg"); [DataField] - public float DoorBlockCheckRange = 0.6f; + public SoundSpecifier AlarmSound = new SoundPathSpecifier("/Audio/_Scp/Effects/announcement.ogg"); + + [DataField] + public float DoorBlockCheckRange = 0.59f; + + [DataField] + public int MaxEntitiesToTeleport = 60; + + [DataField] + public bool TransferGases = false; + + [DataField] + public bool ClearGases = true; public bool IsMoving = false; } \ No newline at end of file diff --git a/Content.Server/_Scp/ComplexElevator/ComplexElevatorSystem.cs b/Content.Server/_Scp/ComplexElevator/ComplexElevatorSystem.cs index 5d42b2e7f4c..196b6cd2a66 100644 --- a/Content.Server/_Scp/ComplexElevator/ComplexElevatorSystem.cs +++ b/Content.Server/_Scp/ComplexElevator/ComplexElevatorSystem.cs @@ -1,18 +1,28 @@ using System.Diagnostics.CodeAnalysis; +using System.Linq; using System.Numerics; using Content.Shared.Timing; using Content.Shared.Damage; using Content.Shared.Damage.Systems; using Content.Shared.Interaction; using Content.Shared.Interaction.Events; +using Content.Shared._Scp.ComplexElevator; using Robust.Shared.Physics.Components; +using Content.Shared.Ghost; +using Robust.Shared.Physics; using Robust.Server.Audio; +using Robust.Shared.Map; +using Robust.Shared.Audio; +using Robust.Shared.Map.Components; using Robust.Server.GameObjects; using Robust.Shared.Audio; -using Robust.Shared.Map; using Robust.Shared.Maths; using Robust.Shared.Timing; using Content.Server.Doors.Systems; +using Content.Server.Atmos.EntitySystems; +using Content.Server.Atmos.Components; +using Content.Shared.Atmos; +using Content.Shared.Atmos.Components; namespace Content.Server._Scp.ComplexElevator; @@ -25,11 +35,8 @@ public sealed class ComplexElevatorSystem : EntitySystem [Dependency] private readonly DamageableSystem _damageable = default!; [Dependency] private readonly UseDelaySystem _useDelay = default!; [Dependency] private readonly AudioSystem _audio = default!; - [Dependency] private readonly PointLightSystem _pointLight = default!; - - private static readonly Color ElevatorButtonGreen = Color.FromHex("#00FF00"); - private static readonly Color ElevatorButtonYellow = Color.FromHex("#FFFF00"); - private static readonly Color ElevatorButtonRed = Color.FromHex("#FF0000"); + [Dependency] private readonly AppearanceSystem _appearance = default!; + [Dependency] private readonly AtmosphereSystem _atmosphere = default!; public override void Initialize() { @@ -39,6 +46,54 @@ public override void Initialize() SubscribeLocalEvent(OnButtonActivate); } + private void SpawnCheckedTimer(Entity ent, TimeSpan delay, Action action) + { + Timer.Spawn(delay, () => + { + if (!Exists(ent) || !ent.Comp.IsMoving) + return; + action(); + }); + } + + private void FailMovement(Entity ent) + { + _audio.PlayPvs(ent.Comp.AlarmSound, ent); + ent.Comp.IsMoving = false; + UpdateButtonLights(ent); + } + + private void StopMovement(Entity ent) + { + ent.Comp.IsMoving = false; + UpdateButtonLights(ent); + } + + private GasMixture CreateReplacementMixture(bool isIntermediate) + { + var mixture = new GasMixture(Atmospherics.CellVolume); + if (isIntermediate) + { + var gasesToRemove = new[] { + Gas.Plasma, Gas.Tritium, Gas.Frezon, Gas.BZ, + Gas.Healium, Gas.Nitrium, Gas.NitrousOxide, Gas.CarbonDioxide + }; + foreach (var gas in gasesToRemove) + { + mixture.Moles[(int)gas] = 0; + } + mixture.Moles[(int)Gas.Nitrogen] = 82; + mixture.Moles[(int)Gas.Oxygen] = 22; + } + else + { + mixture.Moles[(int)Gas.Oxygen] = 1; + mixture.Moles[(int)Gas.Nitrogen] = 1; + } + mixture.Temperature = 293; + return mixture; + } + private TimeSpan GetButtonUseDelay(Entity elevator, ElevatorButtonComponent button) { return elevator.Comp.SendDelay + elevator.Comp.IntermediateDelay + TimeSpan.FromSeconds(1); @@ -54,28 +109,78 @@ private void SetButtonDelay(EntityUid button, Entity e private void StartMovement(Entity ent, string targetFloor) { - KillEntitiesInTargetArea(ent, ent.Comp.IntermediateFloorId); + MoveToFloorImmediate(ent, ent.Comp.IntermediateFloorId); ent.Comp.CurrentFloor = ent.Comp.IntermediateFloorId; - TeleportToFloor(ent, ent.Comp.IntermediateFloorId); _audio.PlayPvs(ent.Comp.TravelSound, ent); + PerformIntermediateMovementCheck(ent, targetFloor); + } + + private void PerformIntermediateMovementCheck(Entity ent, string targetFloor) + { Timer.Spawn(ent.Comp.IntermediateDelay, () => { if (!Exists(ent)) return; - KillEntitiesInTargetArea(ent, targetFloor); + if (!CanMoveWithEntities(ent)) + { + FailMovement(ent); + return; + } + + MoveToFloorImmediate(ent, targetFloor); ent.Comp.CurrentFloor = targetFloor; - TeleportToFloor(ent, targetFloor); OpenDoorsForFloor(ent.Comp.ElevatorId, targetFloor); _audio.PlayPvs(ent.Comp.ArrivalSound, ent); - ent.Comp.IsMoving = false; - UpdateButtonLights(ent); + StopMovement(ent); }); } + private void MoveToFloorImmediate(Entity ent, string floorId) + { + KillEntitiesInTargetArea(ent, floorId); + TeleportToFloor(ent, floorId); + } + + private List GetEntitiesInElevator(EntityUid elevatorUid) + { + var elevatorTransform = Transform(elevatorUid); + var aabb = _lookup.GetWorldAABB(elevatorUid, elevatorTransform); + var intersectingEntities = _lookup.GetEntitiesIntersecting(elevatorTransform.MapID, aabb, LookupFlags.Uncontained); + + var entitiesInElevator = new List(); + foreach (var entUid in intersectingEntities) + { + var entTransform = Transform(entUid); + if (IsEntityValidForTeleport(entUid, elevatorUid, entTransform)) + entitiesInElevator.Add(entUid); + } + return entitiesInElevator; + } + + private bool IsEntityValidForTeleport(EntityUid entUid, EntityUid elevatorUid, TransformComponent? entTransform = null) + { + if (entUid == elevatorUid || HasComp(entUid)) + return false; + + entTransform ??= Transform(entUid); + if (entTransform.Anchored) + return false; + + if (TryComp(entUid, out var physics) && physics.BodyType == BodyType.Static) + return false; + + return true; + } + + private bool CanMoveWithEntities(Entity ent) + { + return GetEntitiesInElevator(ent.Owner).Count(e => !HasComp(e)) <= ent.Comp.MaxEntitiesToTeleport; + } + private void TeleportToFloor(EntityUid uid, string floorId) { var query = EntityQueryEnumerator(); @@ -87,25 +192,65 @@ private void TeleportToFloor(EntityUid uid, string floorId) var pointTransform = Transform(pointUid); var elevatorTransform = Transform(uid); - var aabb = _lookup.GetWorldAABB(uid, elevatorTransform); - var intersectingEntities = _lookup.GetEntitiesIntersecting(elevatorTransform.MapID, aabb, LookupFlags.Dynamic | LookupFlags.Sensors); + var entitiesToTeleport = GetEntitiesInElevator(uid); - var entitiesToTeleport = new List<(EntityUid, Vector2)>(); - foreach (var entUid in intersectingEntities) + var entitiesWithPositions = new List<(EntityUid, Vector2)>(); + foreach (var entUid in entitiesToTeleport) { - if (entUid == uid || HasComp(entUid)) - continue; - var entTransform = Transform(entUid); var relativePos = entTransform.LocalPosition - elevatorTransform.LocalPosition; - entitiesToTeleport.Add((entUid, relativePos)); + entitiesWithPositions.Add((entUid, relativePos)); + } + + if (TryComp(uid, out var elevatorComp) && (elevatorComp.TransferGases || elevatorComp.ClearGases)) + { + var oldElevatorTransform = Transform(uid); + var oldPos = oldElevatorTransform.LocalPosition; + var offset = pointTransform.LocalPosition - oldPos; + + var gridUid = oldElevatorTransform.GridUid; + if (gridUid != null && TryComp(gridUid.Value, out var gridAtmos) && TryComp(gridUid.Value, out var gasOverlay)) + { + var gridEntity = new Entity(gridUid.Value, gridAtmos, gasOverlay); + var aabb = _lookup.GetWorldAABB(uid, oldElevatorTransform); + var minX = (int)Math.Floor(aabb.Left); + var maxX = (int)Math.Ceiling(aabb.Right); + var minY = (int)Math.Floor(aabb.Bottom); + var maxY = (int)Math.Ceiling(aabb.Top); + + for (var x = minX; x < maxX; x++) + { + for (var y = minY; y < maxY; y++) + { + var sourcePos = new Vector2i(x, y); + var targetPos = new Vector2i((int)(x + offset.X), (int)(y + offset.Y)); + var mixture = _atmosphere.GetTileMixture(gridEntity, null, sourcePos); + if (mixture != null) + { + if (elevatorComp.TransferGases) + _atmosphere.SetTileMixture(gridEntity, null, targetPos, mixture.Clone()); + if (elevatorComp.ClearGases) + { + var replacementMixture = CreateReplacementMixture(elevatorComp.CurrentFloor == elevatorComp.IntermediateFloorId); + _atmosphere.SetTileMixture(gridEntity, null, sourcePos, replacementMixture); + if (floorId == elevatorComp.IntermediateFloorId) + { + var targetMixture = CreateReplacementMixture(true); + _atmosphere.SetTileMixture(gridEntity, null, targetPos, targetMixture); + } + } + } + } + } + } } _transform.SetCoordinates(uid, pointTransform.Coordinates); var newElevatorTransform = Transform(uid); + var newPos = newElevatorTransform.LocalPosition; - foreach (var (entUid, relativePos) in entitiesToTeleport) + foreach (var (entUid, relativePos) in entitiesWithPositions) { var newCoordinates = new EntityCoordinates(newElevatorTransform.ParentUid, newElevatorTransform.LocalPosition + relativePos); _transform.SetCoordinates(entUid, newCoordinates); @@ -175,28 +320,21 @@ public void MoveToFloor(Entity ent, string targetFloor return; if (!CanCloseDoorsForFloor(ent.Comp.ElevatorId, ent.Comp.CurrentFloor)) + { + _audio.PlayPvs(ent.Comp.AlarmSound, ent); return; + } ent.Comp.IsMoving = true; UpdateButtonLights(ent); - Timer.Spawn(ent.Comp.SendDelay, () => - { - if (!Exists(ent) || !ent.Comp.IsMoving) - return; - - StartMovement(ent, targetFloor); - }); + SpawnCheckedTimer(ent, ent.Comp.SendDelay, () => StartMovement(ent, targetFloor)); - Timer.Spawn(ent.Comp.DoorCloseDelay, () => + SpawnCheckedTimer(ent, ent.Comp.DoorCloseDelay, () => { - if (!Exists(ent) || !ent.Comp.IsMoving) - return; - if (!CanCloseDoorsForFloor(ent.Comp.ElevatorId, ent.Comp.CurrentFloor)) { - ent.Comp.IsMoving = false; - UpdateButtonLights(ent); + FailMovement(ent); } else { @@ -254,12 +392,9 @@ public void MoveDown(Entity ent) private void OpenDoorsForFloor(string elevatorId, string floor) { - var query = EntityQueryEnumerator(); - while (query.MoveNext(out var doorUid, out var doorComp)) + foreach (var door in GetDoorsForFloor(elevatorId, floor)) { - if (doorComp.ElevatorId != elevatorId || doorComp.Floor != floor) - continue; - _doorSystem.TryOpen(doorUid); + _doorSystem.TryOpen(door); } } @@ -268,12 +403,9 @@ private bool CanCloseDoorsForFloor(string elevatorId, string floor) if (!TryFindElevator(elevatorId, out var elevator)) return true; - var query = EntityQueryEnumerator(); - while (query.MoveNext(out var doorUid, out var doorComp)) + foreach (var door in GetDoorsForFloor(elevatorId, floor)) { - if (doorComp.ElevatorId != elevatorId || doorComp.Floor != floor) - continue; - if (IsDoorBlocked(doorUid, elevator.Value.Comp.DoorBlockCheckRange)) + if (IsDoorBlocked(door, elevator.Value.Comp.DoorBlockCheckRange)) return false; } return true; @@ -285,14 +417,11 @@ private bool TryCloseDoorsForFloor(string elevatorId, string floor) return false; EntityUid? lastDoor = null; - var query = EntityQueryEnumerator(); - while (query.MoveNext(out var doorUid, out var doorComp)) + foreach (var door in GetDoorsForFloor(elevatorId, floor)) { - if (doorComp.ElevatorId != elevatorId || doorComp.Floor != floor) - continue; - if (!_doorSystem.TryClose(doorUid)) + if (!_doorSystem.TryClose(door)) return false; - lastDoor = doorUid; + lastDoor = door; } if (lastDoor.HasValue) @@ -308,7 +437,7 @@ private bool IsDoorBlocked(EntityUid doorUid, float range) if (Deleted(doorUid)) return false; - var intersectingEntities = _lookup.GetEntitiesInRange(Transform(doorUid).Coordinates, range, LookupFlags.Dynamic); + var intersectingEntities = _lookup.GetEntitiesInRange(Transform(doorUid).Coordinates, range, LookupFlags.Dynamic | LookupFlags.Sensors); foreach (var ent in intersectingEntities) { if (ent.Owner != doorUid && !HasComp(ent.Owner)) @@ -317,6 +446,16 @@ private bool IsDoorBlocked(EntityUid doorUid, float range) return false; } + private IEnumerable GetDoorsForFloor(string elevatorId, string floor) + { + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var doorUid, out var doorComp)) + { + if (doorComp.ElevatorId == elevatorId && doorComp.Floor == floor) + yield return doorUid; + } + } + private void KillEntitiesInTargetArea(Entity elevator, string floorId) { var query = EntityQueryEnumerator(); @@ -328,16 +467,16 @@ private void KillEntitiesInTargetArea(Entity elevator, var pointTransform = Transform(pointUid); var aabb = _lookup.GetWorldAABB(elevator.Owner, pointTransform); - var intersectingEntities = _lookup.GetEntitiesIntersecting(pointTransform.MapID, aabb, LookupFlags.Dynamic | LookupFlags.Sensors); + var intersectingEntities = _lookup.GetEntitiesIntersecting(pointTransform.MapID, aabb, LookupFlags.Dynamic); foreach (var entUid in intersectingEntities) { - if (entUid == elevator.Owner) - continue; - - var damage = new DamageSpecifier(); - damage.DamageDict["Blunt"] = 2000; - _damageable.TryChangeDamage(entUid, damage, true); + if (IsEntityValidForTeleport(entUid, elevator.Owner) && !HasComp(entUid)) + { + var damage = new DamageSpecifier(); + damage.DamageDict["Blunt"] = 1000; + _damageable.TryChangeDamage(entUid, damage, true); + } } break; } @@ -345,26 +484,24 @@ private void KillEntitiesInTargetArea(Entity elevator, private void UpdateButtonLights(Entity elevator) { - var query = EntityQueryEnumerator(); - while (query.MoveNext(out var buttonUid, out var buttonComp, out var light)) + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var buttonUid, out var buttonComp)) { if (buttonComp.ElevatorId != elevator.Comp.ElevatorId) continue; - Color color = ElevatorButtonRed; + ElevatorButtonState state = ElevatorButtonState.ElevatorElsewhere; if (buttonComp.ButtonType == ElevatorButtonType.CallButton) { if (elevator.Comp.IsMoving) - color = ElevatorButtonYellow; + state = ElevatorButtonState.ElevatorMoving; else if (buttonComp.Floor == elevator.Comp.CurrentFloor) - color = ElevatorButtonGreen; + state = ElevatorButtonState.ElevatorHere; else - color = ElevatorButtonRed; + state = ElevatorButtonState.ElevatorElsewhere; } - _pointLight.SetColor(buttonUid, color, light); + _appearance.SetData(buttonUid, ElevatorButtonVisuals.ButtonState, state); } } -} - - +} \ No newline at end of file diff --git a/Content.Shared/Construction/SharedConstructionSystem.cs b/Content.Shared/Construction/SharedConstructionSystem.cs index 7f75ba63b86..24585720749 100644 --- a/Content.Shared/Construction/SharedConstructionSystem.cs +++ b/Content.Shared/Construction/SharedConstructionSystem.cs @@ -1,3 +1,4 @@ +using Content.Shared._Scp.Construction; using System.Linq; using Content.Shared.Construction.Components; using Robust.Shared.Map; @@ -9,10 +10,11 @@ namespace Content.Shared.Construction public abstract class SharedConstructionSystem : EntitySystem { [Dependency] private readonly IMapManager _mapManager = default!; - [Dependency] private readonly SharedMapSystem _map = default!; + // fire added + [Dependency] protected readonly SharedMapSystem _map = default!; + // fire end [Dependency] protected readonly IPrototypeManager PrototypeManager = default!; [Dependency] protected readonly SharedTransformSystem TransformSystem = default!; - /// /// Get predicate for construction obstruction checks. /// @@ -23,8 +25,10 @@ public abstract class SharedConstructionSystem : EntitySystem if (!_mapManager.TryFindGridAt(coords, out var gridUid, out var grid)) return null; - - var ignored = _map.GetAnchoredEntities((gridUid, grid), coords).ToHashSet(); + // fire edited + var anchored = _map.GetAnchoredEntities((gridUid, grid), coords); + var ignored = anchored.Where(e => !HasComp(e)).ToHashSet(); + // fire end return e => ignored.Contains(e); } diff --git a/Content.Shared/RCD/Systems/RCDSystem.cs b/Content.Shared/RCD/Systems/RCDSystem.cs index cb8450a5006..c8dc850e124 100644 --- a/Content.Shared/RCD/Systems/RCDSystem.cs +++ b/Content.Shared/RCD/Systems/RCDSystem.cs @@ -13,6 +13,7 @@ using Content.Shared.RCD.Components; using Content.Shared.Tag; using Content.Shared.Tiles; +using Content.Shared._Scp.Construction; using Robust.Shared.Audio.Systems; using Robust.Shared.Map; using Robust.Shared.Map.Components; @@ -425,8 +426,19 @@ private bool IsConstructionLocationValid(EntityUid uid, RCDComponent component, _intersectingEntities.Clear(); _lookup.GetLocalEntitiesIntersecting(gridUid, position, _intersectingEntities, -0.05f, LookupFlags.Uncontained); + foreach (var ent in _intersectingEntities) { + // fire added + if (HasComp(ent)) + { + if (popMsgs) + _popup.PopupClient(Loc.GetString("rcd-component-cannot-build-message"), uid, user); + + return false; + } + // fire end + if (isWindow && HasComp(ent)) continue; diff --git a/Content.Shared/_Scp/ComplexElevator/SharedElevatorButtonVisuals.cs b/Content.Shared/_Scp/ComplexElevator/SharedElevatorButtonVisuals.cs new file mode 100644 index 00000000000..8139971b320 --- /dev/null +++ b/Content.Shared/_Scp/ComplexElevator/SharedElevatorButtonVisuals.cs @@ -0,0 +1,22 @@ +using Robust.Shared.Serialization; + +namespace Content.Shared._Scp.ComplexElevator; + +[Serializable, NetSerializable] +public enum ElevatorButtonVisuals : byte +{ + ButtonState +} + +[Serializable, NetSerializable] +public enum ElevatorButtonState : byte +{ + ElevatorHere, + ElevatorMoving, + ElevatorElsewhere +} + +public enum ElevatorButtonLayers : byte +{ + Base +} \ No newline at end of file diff --git a/Content.Shared/_Scp/Construction/ConstructionBlockerComponent.cs b/Content.Shared/_Scp/Construction/ConstructionBlockerComponent.cs new file mode 100644 index 00000000000..f2ba8d22a33 --- /dev/null +++ b/Content.Shared/_Scp/Construction/ConstructionBlockerComponent.cs @@ -0,0 +1,11 @@ +using Robust.Shared.GameObjects; + +namespace Content.Shared._Scp.Construction; + +/// +/// Component that marks an entity as blocking construction in its tile. +/// +[RegisterComponent] +public sealed partial class ConstructionBlockerComponent : Component +{ +} \ No newline at end of file diff --git a/Resources/Locale/en-US/_strings/construction/construction-system.ftl b/Resources/Locale/en-US/_strings/construction/construction-system.ftl index 81be8c4ab29..8b28510cb08 100644 --- a/Resources/Locale/en-US/_strings/construction/construction-system.ftl +++ b/Resources/Locale/en-US/_strings/construction/construction-system.ftl @@ -1,5 +1,5 @@ ## ConstructionSystem - +construction-system-construct-marker-block = Something is stopping you from building here! construction-system-construct-cannot-start-another-construction = You can't start another construction now! construction-system-construct-no-materials = You don't have the materials to build that! construction-system-already-building = You are already building that! diff --git a/Resources/Locale/en-US/_strings/rcd/components/rcd-component.ftl b/Resources/Locale/en-US/_strings/rcd/components/rcd-component.ftl index 9741bde388c..9a2a9bc9f3c 100644 --- a/Resources/Locale/en-US/_strings/rcd/components/rcd-component.ftl +++ b/Resources/Locale/en-US/_strings/rcd/components/rcd-component.ftl @@ -28,6 +28,7 @@ rcd-component-cannot-build-on-empty-tile-message = You can't build that without rcd-component-must-build-on-subfloor-message = You can only build that on exposed subfloor! rcd-component-cannot-build-on-subfloor-message = You can't build that on exposed subfloor! rcd-component-cannot-build-on-occupied-tile-message = You can't build here, the space is already occupied! +rcd-component-cannot-build-message = Something is stopping you from building here! rcd-component-cannot-build-identical-tile = That tile already exists there! diff --git a/Resources/Locale/ru-RU/_prototypes/_scp/entities/markers/buildblocker.ftl b/Resources/Locale/ru-RU/_prototypes/_scp/entities/markers/buildblocker.ftl new file mode 100644 index 00000000000..18f589e41e9 --- /dev/null +++ b/Resources/Locale/ru-RU/_prototypes/_scp/entities/markers/buildblocker.ftl @@ -0,0 +1,2 @@ +ent-BuildBlocker = Блокировщик строительства + .desc = Не позволяет строить там, где стоит \ No newline at end of file diff --git a/Resources/Locale/ru-RU/_prototypes/_scp/entities/structures/machines/elevator.ftl b/Resources/Locale/ru-RU/_prototypes/_scp/entities/structures/machines/elevator.ftl index 53b094a4652..65789b82740 100644 --- a/Resources/Locale/ru-RU/_prototypes/_scp/entities/structures/machines/elevator.ftl +++ b/Resources/Locale/ru-RU/_prototypes/_scp/entities/structures/machines/elevator.ftl @@ -16,13 +16,13 @@ ent-Elevator_catwalk = { ent-ComplexElevator } ent-Elevator_catwalk_backup = { ent-ComplexElevator } .desc = { ent-ComplexElevator.desc } .suffix = Запасной лифт, сетка -ent-ElevatorButton = кнопка лифта +ent-ElevatorButton = кнопка вызова лифта .desc = кнопка для вызова лифта на ваш этаж. .suffix = Вызов лифта -ent-ElevatorButtonUp = { ent-ElevatorButton } +ent-ElevatorButtonUp = кнопка вызова лифта вверх .desc = кнопка для отправления лифта вверх .suffix = Вверх -ent-ElevatorButtonDown = { ent-ElevatorButton } +ent-ElevatorButtonDown = кнопка вызова лифта вниз .desc = кнопка для отправления лифта вниз. .suffix = Вниз ent-ElevatorBlastDoor = гермозатвор лифта diff --git a/Resources/Locale/ru-RU/_strings/construction/construction-system.ftl b/Resources/Locale/ru-RU/_strings/construction/construction-system.ftl index aaa90dd3857..a0536e410e8 100644 --- a/Resources/Locale/ru-RU/_strings/construction/construction-system.ftl +++ b/Resources/Locale/ru-RU/_strings/construction/construction-system.ftl @@ -1,5 +1,5 @@ ## ConstructionSystem - +construction-system-construct-marker-block = Что-то не даёт здесь строить! construction-system-construct-cannot-start-another-construction = Сейчас вы не можете начать новое строительство! construction-system-construct-no-materials = У вас недостаточно материалов для постройки этого! construction-system-already-building = Вы уже строите это! diff --git a/Resources/Locale/ru-RU/_strings/rcd/components/rcd-component.ftl b/Resources/Locale/ru-RU/_strings/rcd/components/rcd-component.ftl index 9197f3dd219..d34bd70bd60 100644 --- a/Resources/Locale/ru-RU/_strings/rcd/components/rcd-component.ftl +++ b/Resources/Locale/ru-RU/_strings/rcd/components/rcd-component.ftl @@ -23,6 +23,7 @@ rcd-component-cannot-build-on-empty-tile-message = Это не может быт rcd-component-must-build-on-subfloor-message = Это может быть построено только на покрытии! rcd-component-cannot-build-on-subfloor-message = Это не может быть построено на покрытии! rcd-component-cannot-build-on-occupied-tile-message = Здесь нельзя строить, место уже занято! +rcd-component-cannot-build-message = Что-то не даёт здесь строить! rcd-component-cannot-build-identical-tile = Эта клетка уже тут имеется! ### Category names diff --git a/Resources/Prototypes/_Scp/Entities/Markers/construction_blockers.yml b/Resources/Prototypes/_Scp/Entities/Markers/construction_blockers.yml new file mode 100644 index 00000000000..9edf5180f15 --- /dev/null +++ b/Resources/Prototypes/_Scp/Entities/Markers/construction_blockers.yml @@ -0,0 +1,14 @@ +- type: entity + parent: MarkerBase + id: BuildBlocker + name: Build blocker + components: + - type: ConstructionBlocker + - type: Sprite + layers: + - sprite: _Scp/Objects/Markers/environment.rsi + state: base-blue + shader: unshaded + - sprite: _Scp/Objects/Markers/environment.rsi + shader: unshaded + state: wall \ No newline at end of file diff --git a/Resources/Prototypes/_Scp/Entities/Structures/Machines/complex_elevator.yml b/Resources/Prototypes/_Scp/Entities/Structures/Machines/complex_elevator.yml index 10e279f827f..e7ee5ec2a47 100644 --- a/Resources/Prototypes/_Scp/Entities/Structures/Machines/complex_elevator.yml +++ b/Resources/Prototypes/_Scp/Entities/Structures/Machines/complex_elevator.yml @@ -125,7 +125,7 @@ - Complex - type: entity - parent: Elevator_white + parent: Elevator_catwalk id: Elevator_catwalk_backup name: Elevator suffix: Backup elevator, Catwalk @@ -149,13 +149,14 @@ description: Button for controlling the elevator. suffix: "Call button" components: + - type: Godmode + - type: Sprite + drawdepth: SmallObjects + sprite: _Scp/Structures/Wallmounts/elevator_buttons.rsi + state: off - type: InteractionOutline - type: UseDelay delay: 7 - - type: Sprite - drawdepth: SmallObjects - sprite: Structures/Wallmounts/switch.rsi - state: on - type: WallMount arc: 180 - type: ElevatorButton @@ -169,10 +170,15 @@ description: Button for controlling the elevator. suffix: "Call button" components: - - type: PointLight - color: "#FF0000" - radius: 1.4 - energy: 10 + - type: Appearance + - type: ElevatorButtonVisuals + - type: Sprite + drawdepth: SmallObjects + sprite: _Scp/Structures/Wallmounts/elevator_buttons.rsi + layers: + - state: base + - state: elevator_here + map: ["enum.ElevatorButtonLayers.Base"] - type: ElevatorButton elevatorId: "SCP_Elevator_1" buttonType: CallButton @@ -200,6 +206,7 @@ name: Elevator door description: Door that opens when the elevator arrives at the floor. components: + - type: Godmode - type: ElevatorDoor elevatorId: "" floor: "" diff --git a/Resources/Textures/_Scp/Structures/Wallmounts/elevator_buttons.rsi/base.png b/Resources/Textures/_Scp/Structures/Wallmounts/elevator_buttons.rsi/base.png new file mode 100644 index 00000000000..dd678c5836d Binary files /dev/null and b/Resources/Textures/_Scp/Structures/Wallmounts/elevator_buttons.rsi/base.png differ diff --git a/Resources/Textures/_Scp/Structures/Wallmounts/elevator_buttons.rsi/elevator_elsewhere.png b/Resources/Textures/_Scp/Structures/Wallmounts/elevator_buttons.rsi/elevator_elsewhere.png new file mode 100644 index 00000000000..93158fd2ff4 Binary files /dev/null and b/Resources/Textures/_Scp/Structures/Wallmounts/elevator_buttons.rsi/elevator_elsewhere.png differ diff --git a/Resources/Textures/_Scp/Structures/Wallmounts/elevator_buttons.rsi/elevator_here.png b/Resources/Textures/_Scp/Structures/Wallmounts/elevator_buttons.rsi/elevator_here.png new file mode 100644 index 00000000000..d038a122ab0 Binary files /dev/null and b/Resources/Textures/_Scp/Structures/Wallmounts/elevator_buttons.rsi/elevator_here.png differ diff --git a/Resources/Textures/_Scp/Structures/Wallmounts/elevator_buttons.rsi/elevator_moving.png b/Resources/Textures/_Scp/Structures/Wallmounts/elevator_buttons.rsi/elevator_moving.png new file mode 100644 index 00000000000..faa906851a4 Binary files /dev/null and b/Resources/Textures/_Scp/Structures/Wallmounts/elevator_buttons.rsi/elevator_moving.png differ diff --git a/Resources/Textures/_Scp/Structures/Wallmounts/elevator_buttons.rsi/meta.json b/Resources/Textures/_Scp/Structures/Wallmounts/elevator_buttons.rsi/meta.json new file mode 100644 index 00000000000..db3704a51c0 --- /dev/null +++ b/Resources/Textures/_Scp/Structures/Wallmounts/elevator_buttons.rsi/meta.json @@ -0,0 +1,101 @@ +{ + "license": "CC-BY-SA-3.0", + "copyright": "Sprited by discord: neyran.official", + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "base", + "directions": 4, + "delays": [ + [ + 1 + ], + [ + 1 + ], + [ + 1 + ], + [ + 1 + ] + ] + }, + { + "name": "off", + "directions": 4, + "delays": [ + [ + 1 + ], + [ + 1 + ], + [ + 1 + ], + [ + 1 + ] + ] + }, + { + "name": "elevator_elsewhere", + "directions": 4, + "delays": [ + [ + 1 + ], + [ + 1 + ], + [ + 1 + ], + [ + 1 + ] + ] + }, + { + "name": "elevator_moving", + "directions": 4, + "delays": [ + [ + 1 + ], + [ + 1 + ], + [ + 1 + ], + [ + 1 + ] + ] + }, + { + "name": "elevator_here", + "directions": 4, + "delays": [ + [ + 1 + ], + [ + 1 + ], + [ + 1 + ], + [ + 1 + ] + ] + } + ] +} diff --git a/Resources/Textures/_Scp/Structures/Wallmounts/elevator_buttons.rsi/off.png b/Resources/Textures/_Scp/Structures/Wallmounts/elevator_buttons.rsi/off.png new file mode 100644 index 00000000000..de88854941c Binary files /dev/null and b/Resources/Textures/_Scp/Structures/Wallmounts/elevator_buttons.rsi/off.png differ