From fcdc1efe16694bbf354879913ae32281b32f1a2f Mon Sep 17 00:00:00 2001 From: Neyran Date: Sat, 11 Oct 2025 22:14:15 +0300 Subject: [PATCH 01/10] =?UTF-8?q?1=20=D0=AD=D1=82=D0=B0=D0=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Кнопки и двери лифтов более не ломаемые. 2. Лифт может перевозить предметы и не только. 3. Ограничение на количество перевозимых лифтом сущностей 4. Звуковое оповещение если двери лифта заблокированы или перегруз. 5. Лифт удалят предметы на промежуточном этаже. --- .../ComplexElevatorComponent.cs | 8 +- .../ComplexElevator/ComplexElevatorSystem.cs | 145 +++++++++++++----- .../Structures/Machines/complex_elevator.yml | 4 +- 3 files changed, 113 insertions(+), 44 deletions(-) diff --git a/Content.Server/_Scp/ComplexElevator/ComplexElevatorComponent.cs b/Content.Server/_Scp/ComplexElevator/ComplexElevatorComponent.cs index 56c7adf0e6c..d9b175064b9 100644 --- a/Content.Server/_Scp/ComplexElevator/ComplexElevatorComponent.cs +++ b/Content.Server/_Scp/ComplexElevator/ComplexElevatorComponent.cs @@ -39,7 +39,13 @@ 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/Machines/anomaly_sync_connect.ogg"); + + [DataField] + public float DoorBlockCheckRange = 0.59f; + + [DataField] + public int MaxEntitiesToTeleport = 150; 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..bd837fc3879 100644 --- a/Content.Server/_Scp/ComplexElevator/ComplexElevatorSystem.cs +++ b/Content.Server/_Scp/ComplexElevator/ComplexElevatorSystem.cs @@ -6,10 +6,12 @@ using Content.Shared.Interaction; using Content.Shared.Interaction.Events; using Robust.Shared.Physics.Components; +using Robust.Shared.Physics; using Robust.Server.Audio; +using Robust.Shared.Map; +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; @@ -54,9 +56,16 @@ private void SetButtonDelay(EntityUid button, Entity e private void StartMovement(Entity ent, string targetFloor) { - KillEntitiesInTargetArea(ent, ent.Comp.IntermediateFloorId); + if (!CanMoveWithEntities(ent)) + { + _audio.PlayPvs(ent.Comp.AlarmSound, ent); + ent.Comp.IsMoving = false; + UpdateButtonLights(ent); + return; + } + + MoveToFloorImmediate(ent, ent.Comp.IntermediateFloorId, false); ent.Comp.CurrentFloor = ent.Comp.IntermediateFloorId; - TeleportToFloor(ent, ent.Comp.IntermediateFloorId); _audio.PlayPvs(ent.Comp.TravelSound, ent); Timer.Spawn(ent.Comp.IntermediateDelay, () => @@ -64,9 +73,8 @@ private void StartMovement(Entity ent, string targetFl if (!Exists(ent)) return; - KillEntitiesInTargetArea(ent, targetFloor); + MoveToFloorImmediate(ent, targetFloor); ent.Comp.CurrentFloor = targetFloor; - TeleportToFloor(ent, targetFloor); OpenDoorsForFloor(ent.Comp.ElevatorId, targetFloor); _audio.PlayPvs(ent.Comp.ArrivalSound, ent); @@ -76,6 +84,47 @@ private void StartMovement(Entity ent, string targetFl }); } + private void MoveToFloorImmediate(Entity ent, string floorId, bool shouldKill = true) + { + KillEntitiesInTargetArea(ent, floorId, shouldKill); + 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) + { + if (IsEntityValidForTeleport(entUid, elevatorUid)) + entitiesInElevator.Add(entUid); + } + return entitiesInElevator; + } + + private bool IsEntityValidForTeleport(EntityUid entUid, EntityUid elevatorUid) + { + if (entUid == elevatorUid || HasComp(entUid)) + return false; + + var 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 <= ent.Comp.MaxEntitiesToTeleport; + } + private void TeleportToFloor(EntityUid uid, string floorId) { var query = EntityQueryEnumerator(); @@ -87,25 +136,21 @@ 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)); } _transform.SetCoordinates(uid, pointTransform.Coordinates); var newElevatorTransform = Transform(uid); - 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,7 +220,16 @@ public void MoveToFloor(Entity ent, string targetFloor return; if (!CanCloseDoorsForFloor(ent.Comp.ElevatorId, ent.Comp.CurrentFloor)) + { + _audio.PlayPvs(ent.Comp.AlarmSound, ent); + return; + } + + if (!CanMoveWithEntities(ent)) + { + _audio.PlayPvs(ent.Comp.AlarmSound, ent); return; + } ent.Comp.IsMoving = true; UpdateButtonLights(ent); @@ -195,6 +249,7 @@ public void MoveToFloor(Entity ent, string targetFloor if (!CanCloseDoorsForFloor(ent.Comp.ElevatorId, ent.Comp.CurrentFloor)) { + _audio.PlayPvs(ent.Comp.AlarmSound, ent); ent.Comp.IsMoving = false; UpdateButtonLights(ent); } @@ -254,12 +309,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 +320,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 +334,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 +354,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,7 +363,17 @@ private bool IsDoorBlocked(EntityUid doorUid, float range) return false; } - private void KillEntitiesInTargetArea(Entity elevator, string floorId) + 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, bool shouldKill = true) { var query = EntityQueryEnumerator(); while (query.MoveNext(out var pointUid, out var pointComp)) @@ -328,16 +384,23 @@ 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)) + { + if (shouldKill) + { + var damage = new DamageSpecifier(); + damage.DamageDict["Blunt"] = 1000; + _damageable.TryChangeDamage(entUid, damage, true); + } + else + { + Del(entUid); + } + } } break; } @@ -365,6 +428,4 @@ private void UpdateButtonLights(Entity elevator) _pointLight.SetColor(buttonUid, color, light); } } -} - - +} \ 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..5461ca46ab1 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,6 +149,7 @@ description: Button for controlling the elevator. suffix: "Call button" components: + - type: Godmode - type: InteractionOutline - type: UseDelay delay: 7 @@ -200,6 +201,7 @@ name: Elevator door description: Door that opens when the elevator arrives at the floor. components: + - type: Godmode - type: ElevatorDoor elevatorId: "" floor: "" From 67a8dfe8b8dd5dea0ea7cff7ea89b09bdb21daf1 Mon Sep 17 00:00:00 2001 From: Neyran Date: Sun, 12 Oct 2025 04:50:21 +0300 Subject: [PATCH 02/10] =?UTF-8?q?2=20=D0=AD=D1=82=D0=B0=D0=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Спрайты для кнопок лифта 2. Визуализатор для состояний кнопки вызова лифта. 3. Лифт более не учитывает призраков при расчетах лимитов переноса 4. Убрано то что лифт удаляет что либо на промежуточном этаже (На доработку) 5. Исправлен спрайт у Elevator_catwalk_backup --- .../ElevatorButtonVisualizerSystem.cs | 19 ++++ .../ElevatorButtonVisualsComponent.cs | 19 ++++ .../ComplexElevatorComponent.cs | 2 +- .../ComplexElevator/ComplexElevatorSystem.cs | 75 +++++++------ .../SharedElevatorButtonVisuals.cs | 22 ++++ .../entities/structures/machines/elevator.ftl | 6 +- .../Structures/Machines/complex_elevator.yml | 21 ++-- .../Wallmounts/elevator_buttons.rsi/base.png | Bin 0 -> 720 bytes .../elevator_elsewhere.png | Bin 0 -> 523 bytes .../elevator_buttons.rsi/elevator_here.png | Bin 0 -> 524 bytes .../elevator_buttons.rsi/elevator_moving.png | Bin 0 -> 524 bytes .../Wallmounts/elevator_buttons.rsi/meta.json | 101 ++++++++++++++++++ .../Wallmounts/elevator_buttons.rsi/off.png | Bin 0 -> 754 bytes 13 files changed, 214 insertions(+), 51 deletions(-) create mode 100644 Content.Client/_Scp/ComplexElevator/Visualizers/ElevatorButtonVisualizerSystem.cs create mode 100644 Content.Client/_Scp/ComplexElevator/Visualizers/ElevatorButtonVisualsComponent.cs create mode 100644 Content.Shared/_Scp/ComplexElevator/SharedElevatorButtonVisuals.cs create mode 100644 Resources/Textures/_Scp/Structures/Wallmounts/elevator_buttons.rsi/base.png create mode 100644 Resources/Textures/_Scp/Structures/Wallmounts/elevator_buttons.rsi/elevator_elsewhere.png create mode 100644 Resources/Textures/_Scp/Structures/Wallmounts/elevator_buttons.rsi/elevator_here.png create mode 100644 Resources/Textures/_Scp/Structures/Wallmounts/elevator_buttons.rsi/elevator_moving.png create mode 100644 Resources/Textures/_Scp/Structures/Wallmounts/elevator_buttons.rsi/meta.json create mode 100644 Resources/Textures/_Scp/Structures/Wallmounts/elevator_buttons.rsi/off.png 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/_Scp/ComplexElevator/ComplexElevatorComponent.cs b/Content.Server/_Scp/ComplexElevator/ComplexElevatorComponent.cs index d9b175064b9..d4c1ab472f6 100644 --- a/Content.Server/_Scp/ComplexElevator/ComplexElevatorComponent.cs +++ b/Content.Server/_Scp/ComplexElevator/ComplexElevatorComponent.cs @@ -45,7 +45,7 @@ public sealed partial class ComplexElevatorComponent : Component public float DoorBlockCheckRange = 0.59f; [DataField] - public int MaxEntitiesToTeleport = 150; + public int MaxEntitiesToTeleport = 60; 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 bd837fc3879..d90718ddb81 100644 --- a/Content.Server/_Scp/ComplexElevator/ComplexElevatorSystem.cs +++ b/Content.Server/_Scp/ComplexElevator/ComplexElevatorSystem.cs @@ -1,11 +1,15 @@ 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 Content.Server.Ghost; using Robust.Shared.Physics.Components; +using Content.Shared.Ghost; using Robust.Shared.Physics; using Robust.Server.Audio; using Robust.Shared.Map; @@ -27,11 +31,7 @@ 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!; public override void Initialize() { @@ -56,14 +56,6 @@ private void SetButtonDelay(EntityUid button, Entity e private void StartMovement(Entity ent, string targetFloor) { - if (!CanMoveWithEntities(ent)) - { - _audio.PlayPvs(ent.Comp.AlarmSound, ent); - ent.Comp.IsMoving = false; - UpdateButtonLights(ent); - return; - } - MoveToFloorImmediate(ent, ent.Comp.IntermediateFloorId, false); ent.Comp.CurrentFloor = ent.Comp.IntermediateFloorId; @@ -73,6 +65,14 @@ private void StartMovement(Entity ent, string targetFl if (!Exists(ent)) return; + if (!CanMoveWithEntities(ent)) + { + _audio.PlayPvs(ent.Comp.AlarmSound, ent); + ent.Comp.IsMoving = false; + UpdateButtonLights(ent); + return; + } + MoveToFloorImmediate(ent, targetFloor); ent.Comp.CurrentFloor = targetFloor; OpenDoorsForFloor(ent.Comp.ElevatorId, targetFloor); @@ -86,7 +86,7 @@ private void StartMovement(Entity ent, string targetFl private void MoveToFloorImmediate(Entity ent, string floorId, bool shouldKill = true) { - KillEntitiesInTargetArea(ent, floorId, shouldKill); + KillEntitiesInTargetArea(ent, floorId); TeleportToFloor(ent, floorId); } @@ -122,7 +122,17 @@ private bool IsEntityValidForTeleport(EntityUid entUid, EntityUid elevatorUid) private bool CanMoveWithEntities(Entity ent) { - return GetEntitiesInElevator(ent.Owner).Count <= ent.Comp.MaxEntitiesToTeleport; + var elevatorTransform = Transform(ent.Owner); + var aabb = _lookup.GetWorldAABB(ent.Owner, elevatorTransform); + var intersectingEntities = _lookup.GetEntitiesIntersecting(elevatorTransform.MapID, aabb, LookupFlags.Uncontained); + + foreach (var entUid in intersectingEntities) + { + if (entUid == ent.Owner || HasComp(entUid)) + continue; + } + + return GetEntitiesInElevator(ent.Owner).Count(e => !HasComp(e)) < ent.Comp.MaxEntitiesToTeleport; } private void TeleportToFloor(EntityUid uid, string floorId) @@ -225,12 +235,6 @@ public void MoveToFloor(Entity ent, string targetFloor return; } - if (!CanMoveWithEntities(ent)) - { - _audio.PlayPvs(ent.Comp.AlarmSound, ent); - return; - } - ent.Comp.IsMoving = true; UpdateButtonLights(ent); @@ -373,7 +377,7 @@ private IEnumerable GetDoorsForFloor(string elevatorId, string floor) } } - private void KillEntitiesInTargetArea(Entity elevator, string floorId, bool shouldKill = true) + private void KillEntitiesInTargetArea(Entity elevator, string floorId) { var query = EntityQueryEnumerator(); while (query.MoveNext(out var pointUid, out var pointComp)) @@ -390,16 +394,9 @@ private void KillEntitiesInTargetArea(Entity elevator, { if (IsEntityValidForTeleport(entUid, elevator.Owner)) { - if (shouldKill) - { - var damage = new DamageSpecifier(); - damage.DamageDict["Blunt"] = 1000; - _damageable.TryChangeDamage(entUid, damage, true); - } - else - { - Del(entUid); - } + var damage = new DamageSpecifier(); + damage.DamageDict["Blunt"] = 1000; + _damageable.TryChangeDamage(entUid, damage, true); } } break; @@ -408,24 +405,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/_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/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/Prototypes/_Scp/Entities/Structures/Machines/complex_elevator.yml b/Resources/Prototypes/_Scp/Entities/Structures/Machines/complex_elevator.yml index 5461ca46ab1..bf96a8cc0a8 100644 --- a/Resources/Prototypes/_Scp/Entities/Structures/Machines/complex_elevator.yml +++ b/Resources/Prototypes/_Scp/Entities/Structures/Machines/complex_elevator.yml @@ -150,13 +150,13 @@ 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 @@ -170,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_moving + map: ["enum.ElevatorButtonLayers.Base"] - type: ElevatorButton elevatorId: "SCP_Elevator_1" buttonType: CallButton 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 0000000000000000000000000000000000000000..dd678c5836d3fd0325a9e5b6ca8d5ba6dc0caa43 GIT binary patch literal 720 zcmV;>0x$iEP)e@h?~1#i%8_!LW|gUxew>wb9nE8K+4oCw<8W#*>lp#guI;1$)Oj* zbkawZ4n=eA`Ng>mZRhh2Nu0Mak=6d)ztf%9T@9o#Fs0d!2ht3XTJvndTfl%;RPrDl z0^`ndHV4v`(A7FW3og|8U9gi$&q6?C%7qqITUaYP76itCsAX2Q#y;XFJ$iX*5f}o7 zaY>UTfs9I(5+)uoN|d3EFaGOWpn{A>1)CZUB?=Vr7)Pdxi;j$egN}|#P4xb^PuG~7 zsHgWNp!3Q1-$o#`1K-=e|8?a1-^UPqgo|?1Upa*74+w5IwdesvHsI{Csj0hgz6pa5 zw&EziQV<9j2E3j^Zx;G*plhYxRpXwMd&sOq>KgX;Vbp-g>JP;nXYVhSS{?uZ0VPR9 zK~#90?b=hsZ+8>;hsn2dl{Fj7BW{4}1|)jDPO7mqa=Qo)M+4U_ zxTmoX0000G`G<{&C=k&MBwQ1}3upxru89H>%|ODnT)qx#;s!{HGy@6O#ET$-#GmW~ z0000006_8lB*#CV!pIn7mdnj+>=~JT`gUMbEAf+mg!~|U`);t`?o!2QHnkG!sqm+W zEa|*WtrW4i_JqTJH}N@5I&V`eRro~^000003h4n_-hb(?ZlL)90000 C8%TBl literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..93158fd2ff4d2308c91f9f9f4b115305a5aba6bb GIT binary patch literal 523 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 literal 0 HcmV?d00001 From 81f51f71748d4c96f7d75f0941440289a88d3b61 Mon Sep 17 00:00:00 2001 From: Neyran Date: Sun, 12 Oct 2025 06:04:00 +0300 Subject: [PATCH 03/10] =?UTF-8?q?3=20=D0=AD=D1=82=D0=B0=D0=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Маркер блокировщика строительства что не позволяет строить там где он стоит. --- .../Construction/ConstructionSystem.Initial.cs | 17 ++++++++++++++++- .../Construction/SharedConstructionSystem.cs | 12 ++++++++---- Content.Shared/RCD/Systems/RCDSystem.cs | 12 ++++++++++++ .../ConstructionBlockerComponent.cs | 11 +++++++++++ .../construction/construction-system.ftl | 2 +- .../_strings/rcd/components/rcd-component.ftl | 1 + .../_scp/entities/markers/buildblocker.ftl | 2 ++ .../construction/construction-system.ftl | 2 +- .../_strings/rcd/components/rcd-component.ftl | 1 + .../Entities/Markers/construction_blockers.yml | 14 ++++++++++++++ 10 files changed, 67 insertions(+), 7 deletions(-) create mode 100644 Content.Shared/_Scp/Construction/ConstructionBlockerComponent.cs create mode 100644 Resources/Locale/ru-RU/_prototypes/_scp/entities/markers/buildblocker.ftl create mode 100644 Resources/Prototypes/_Scp/Entities/Markers/construction_blockers.yml 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.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/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..e5f587eabab --- /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/_strings/construction/construction-system.ftl b/Resources/Locale/ru-RU/_strings/construction/construction-system.ftl index aaa90dd3857..dbfb8529c35 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..f37eaf7180d 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 From a3e28bce6edd8711f6d9d7d707ddb715b5210275 Mon Sep 17 00:00:00 2001 From: Neyran Date: Sun, 12 Oct 2025 07:52:53 +0300 Subject: [PATCH 04/10] =?UTF-8?q?=D0=AD=D1=82=D0=B0=D0=BF=203.5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Изменение базового спрайта кнопки вызова лифта. 2. Улучшение читаемости кода. --- .../ComplexElevator/ComplexElevatorSystem.cs | 52 ++++++++++++------- .../Structures/Machines/complex_elevator.yml | 2 +- 2 files changed, 34 insertions(+), 20 deletions(-) diff --git a/Content.Server/_Scp/ComplexElevator/ComplexElevatorSystem.cs b/Content.Server/_Scp/ComplexElevator/ComplexElevatorSystem.cs index d90718ddb81..11a0f316387 100644 --- a/Content.Server/_Scp/ComplexElevator/ComplexElevatorSystem.cs +++ b/Content.Server/_Scp/ComplexElevator/ComplexElevatorSystem.cs @@ -41,6 +41,29 @@ 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 TimeSpan GetButtonUseDelay(Entity elevator, ElevatorButtonComponent button) { return elevator.Comp.SendDelay + elevator.Comp.IntermediateDelay + TimeSpan.FromSeconds(1); @@ -60,6 +83,11 @@ private void StartMovement(Entity ent, string targetFl ent.Comp.CurrentFloor = 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)) @@ -67,9 +95,7 @@ private void StartMovement(Entity ent, string targetFl if (!CanMoveWithEntities(ent)) { - _audio.PlayPvs(ent.Comp.AlarmSound, ent); - ent.Comp.IsMoving = false; - UpdateButtonLights(ent); + FailMovement(ent); return; } @@ -79,8 +105,7 @@ private void StartMovement(Entity ent, string targetFl _audio.PlayPvs(ent.Comp.ArrivalSound, ent); - ent.Comp.IsMoving = false; - UpdateButtonLights(ent); + StopMovement(ent); }); } @@ -238,24 +263,13 @@ public void MoveToFloor(Entity ent, string targetFloor 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)) { - _audio.PlayPvs(ent.Comp.AlarmSound, ent); - ent.Comp.IsMoving = false; - UpdateButtonLights(ent); + FailMovement(ent); } else { diff --git a/Resources/Prototypes/_Scp/Entities/Structures/Machines/complex_elevator.yml b/Resources/Prototypes/_Scp/Entities/Structures/Machines/complex_elevator.yml index bf96a8cc0a8..e7ee5ec2a47 100644 --- a/Resources/Prototypes/_Scp/Entities/Structures/Machines/complex_elevator.yml +++ b/Resources/Prototypes/_Scp/Entities/Structures/Machines/complex_elevator.yml @@ -177,7 +177,7 @@ sprite: _Scp/Structures/Wallmounts/elevator_buttons.rsi layers: - state: base - - state: elevator_moving + - state: elevator_here map: ["enum.ElevatorButtonLayers.Base"] - type: ElevatorButton elevatorId: "SCP_Elevator_1" From 8c2bb56daf244af998c1ca139574b58490ffaaf1 Mon Sep 17 00:00:00 2001 From: Neyran Date: Sun, 12 Oct 2025 09:51:10 +0300 Subject: [PATCH 05/10] =?UTF-8?q?4=20=D0=AD=D1=82=D0=B0=D0=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Перенос газов между этажами лифта. 2. Очистка промежуточного этажа от не нужных газов. 3. Поля для включения переноса газов а так же очистки промежуточного этажа от нежелательных газов. 4. метод SetTileMixtureв AtmosphereSystem.API.cs для установки газов на тайле. 5. Заменен звук звукового сигнала лифта при перегрузке или заблокированных дверях. --- .../EntitySystems/AtmosphereSystem.API.cs | 13 ++++ .../ComplexElevatorComponent.cs | 8 +- .../ComplexElevator/ComplexElevatorSystem.cs | 73 ++++++++++++++++++- 3 files changed, 92 insertions(+), 2 deletions(-) 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/_Scp/ComplexElevator/ComplexElevatorComponent.cs b/Content.Server/_Scp/ComplexElevator/ComplexElevatorComponent.cs index d4c1ab472f6..bb8e733f254 100644 --- a/Content.Server/_Scp/ComplexElevator/ComplexElevatorComponent.cs +++ b/Content.Server/_Scp/ComplexElevator/ComplexElevatorComponent.cs @@ -39,7 +39,7 @@ public sealed partial class ComplexElevatorComponent : Component public SoundSpecifier ArrivalSound = new SoundPathSpecifier("/Audio/_Scp/Machines/Elevator/Beep-elevator.ogg"); [DataField] - public SoundSpecifier AlarmSound = new SoundPathSpecifier("/Audio/Machines/anomaly_sync_connect.ogg"); + public SoundSpecifier AlarmSound = new SoundPathSpecifier("/Audio/_Scp/Effects/announcement.ogg"); [DataField] public float DoorBlockCheckRange = 0.59f; @@ -47,5 +47,11 @@ public sealed partial class ComplexElevatorComponent : Component [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 11a0f316387..8de2a9b1808 100644 --- a/Content.Server/_Scp/ComplexElevator/ComplexElevatorSystem.cs +++ b/Content.Server/_Scp/ComplexElevator/ComplexElevatorSystem.cs @@ -7,18 +7,22 @@ using Content.Shared.Interaction; using Content.Shared.Interaction.Events; using Content.Shared._Scp.ComplexElevator; -using Content.Server.Ghost; 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.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; @@ -32,6 +36,7 @@ public sealed class ComplexElevatorSystem : EntitySystem [Dependency] private readonly UseDelaySystem _useDelay = default!; [Dependency] private readonly AudioSystem _audio = default!; [Dependency] private readonly AppearanceSystem _appearance = default!; + [Dependency] private readonly AtmosphereSystem _atmosphere = default!; public override void Initialize() { @@ -64,6 +69,28 @@ private void StopMovement(Entity ent) UpdateButtonLights(ent); } + private GasMixture CreateReplacementMixture(bool isIntermediate) + { + var mixture = new GasMixture(Atmospherics.CellVolume); + if (isIntermediate) + { + int[] gasesToRemove = { 3, 4, 8, 9, 10, 11, 7, 2 }; + foreach (var gasId in gasesToRemove) + { + mixture.Moles[gasId] = 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); @@ -181,9 +208,53 @@ private void TeleportToFloor(EntityUid uid, string floorId) 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 && elevatorComp.ClearGases) + { + 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 entitiesWithPositions) { From bdb1f405fbaa30c5b0ffc8795ee99e5baab0dd07 Mon Sep 17 00:00:00 2001 From: Neyran Date: Sun, 12 Oct 2025 10:05:54 +0300 Subject: [PATCH 06/10] Update ComplexElevatorSystem.cs --- Content.Server/_Scp/ComplexElevator/ComplexElevatorSystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Server/_Scp/ComplexElevator/ComplexElevatorSystem.cs b/Content.Server/_Scp/ComplexElevator/ComplexElevatorSystem.cs index 8de2a9b1808..11d03f37184 100644 --- a/Content.Server/_Scp/ComplexElevator/ComplexElevatorSystem.cs +++ b/Content.Server/_Scp/ComplexElevator/ComplexElevatorSystem.cs @@ -136,7 +136,7 @@ private void PerformIntermediateMovementCheck(Entity e }); } - private void MoveToFloorImmediate(Entity ent, string floorId, bool shouldKill = true) + private void MoveToFloorImmediate(Entity ent, string floorId) { KillEntitiesInTargetArea(ent, floorId); TeleportToFloor(ent, floorId); From b05f86d44238229d8457eb25cfa82c9279bd959f Mon Sep 17 00:00:00 2001 From: Neyran Date: Sun, 12 Oct 2025 10:09:14 +0300 Subject: [PATCH 07/10] =?UTF-8?q?=D0=BF=D1=80=D0=B0=D0=B2=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Content.Server/_Scp/ComplexElevator/ComplexElevatorSystem.cs | 2 +- .../ru-RU/_prototypes/_scp/entities/markers/buildblocker.ftl | 2 +- .../Locale/ru-RU/_strings/construction/construction-system.ftl | 2 +- .../Locale/ru-RU/_strings/rcd/components/rcd-component.ftl | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Content.Server/_Scp/ComplexElevator/ComplexElevatorSystem.cs b/Content.Server/_Scp/ComplexElevator/ComplexElevatorSystem.cs index 11d03f37184..fcddf0099aa 100644 --- a/Content.Server/_Scp/ComplexElevator/ComplexElevatorSystem.cs +++ b/Content.Server/_Scp/ComplexElevator/ComplexElevatorSystem.cs @@ -184,7 +184,7 @@ private bool CanMoveWithEntities(Entity ent) continue; } - return GetEntitiesInElevator(ent.Owner).Count(e => !HasComp(e)) < ent.Comp.MaxEntitiesToTeleport; + return GetEntitiesInElevator(ent.Owner).Count(e => !HasComp(e)) <= ent.Comp.MaxEntitiesToTeleport; } private void TeleportToFloor(EntityUid uid, string floorId) diff --git a/Resources/Locale/ru-RU/_prototypes/_scp/entities/markers/buildblocker.ftl b/Resources/Locale/ru-RU/_prototypes/_scp/entities/markers/buildblocker.ftl index e5f587eabab..18f589e41e9 100644 --- a/Resources/Locale/ru-RU/_prototypes/_scp/entities/markers/buildblocker.ftl +++ b/Resources/Locale/ru-RU/_prototypes/_scp/entities/markers/buildblocker.ftl @@ -1,2 +1,2 @@ ent-BuildBlocker = Блокировщик строительства - .desc = Не позволяет строить там где стоит \ No newline at end of file + .desc = Не позволяет строить там, где стоит \ No newline at end of file diff --git a/Resources/Locale/ru-RU/_strings/construction/construction-system.ftl b/Resources/Locale/ru-RU/_strings/construction/construction-system.ftl index dbfb8529c35..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-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 f37eaf7180d..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,7 +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-message = Что-то не даёт здесь строить! rcd-component-cannot-build-identical-tile = Эта клетка уже тут имеется! ### Category names From 1b199cd72f557fd173b00008600e7b033e79e24b Mon Sep 17 00:00:00 2001 From: Neyran Date: Sun, 12 Oct 2025 10:14:23 +0300 Subject: [PATCH 08/10] Update ComplexElevatorSystem.cs --- Content.Server/_Scp/ComplexElevator/ComplexElevatorSystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Server/_Scp/ComplexElevator/ComplexElevatorSystem.cs b/Content.Server/_Scp/ComplexElevator/ComplexElevatorSystem.cs index fcddf0099aa..83b8614fcd0 100644 --- a/Content.Server/_Scp/ComplexElevator/ComplexElevatorSystem.cs +++ b/Content.Server/_Scp/ComplexElevator/ComplexElevatorSystem.cs @@ -106,7 +106,7 @@ private void SetButtonDelay(EntityUid button, Entity e private void StartMovement(Entity ent, string targetFloor) { - MoveToFloorImmediate(ent, ent.Comp.IntermediateFloorId, false); + MoveToFloorImmediate(ent, ent.Comp.IntermediateFloorId); ent.Comp.CurrentFloor = ent.Comp.IntermediateFloorId; _audio.PlayPvs(ent.Comp.TravelSound, ent); From 7bcd3f7a74574d5c7a01750867c1339550845678 Mon Sep 17 00:00:00 2001 From: Neyran Date: Sun, 12 Oct 2025 18:35:13 +0300 Subject: [PATCH 09/10] Update ComplexElevatorSystem.cs --- .../ComplexElevator/ComplexElevatorSystem.cs | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/Content.Server/_Scp/ComplexElevator/ComplexElevatorSystem.cs b/Content.Server/_Scp/ComplexElevator/ComplexElevatorSystem.cs index 83b8614fcd0..cdb85c01c74 100644 --- a/Content.Server/_Scp/ComplexElevator/ComplexElevatorSystem.cs +++ b/Content.Server/_Scp/ComplexElevator/ComplexElevatorSystem.cs @@ -74,10 +74,13 @@ private GasMixture CreateReplacementMixture(bool isIntermediate) var mixture = new GasMixture(Atmospherics.CellVolume); if (isIntermediate) { - int[] gasesToRemove = { 3, 4, 8, 9, 10, 11, 7, 2 }; - foreach (var gasId in gasesToRemove) + 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[gasId] = 0; + mixture.Moles[(int)gas] = 0; } mixture.Moles[(int)Gas.Nitrogen] = 82; mixture.Moles[(int)Gas.Oxygen] = 22; @@ -151,18 +154,19 @@ private List GetEntitiesInElevator(EntityUid elevatorUid) var entitiesInElevator = new List(); foreach (var entUid in intersectingEntities) { - if (IsEntityValidForTeleport(entUid, elevatorUid)) + var entTransform = Transform(entUid); + if (IsEntityValidForTeleport(entUid, elevatorUid, entTransform)) entitiesInElevator.Add(entUid); } return entitiesInElevator; } - private bool IsEntityValidForTeleport(EntityUid entUid, EntityUid elevatorUid) + private bool IsEntityValidForTeleport(EntityUid entUid, EntityUid elevatorUid, TransformComponent? entTransform = null) { if (entUid == elevatorUid || HasComp(entUid)) return false; - var entTransform = Transform(entUid); + entTransform ??= Transform(entUid); if (entTransform.Anchored) return false; @@ -239,11 +243,11 @@ private void TeleportToFloor(EntityUid uid, string floorId) { var replacementMixture = CreateReplacementMixture(elevatorComp.CurrentFloor == elevatorComp.IntermediateFloorId); _atmosphere.SetTileMixture(gridEntity, null, sourcePos, replacementMixture); - } - if (floorId == elevatorComp.IntermediateFloorId && elevatorComp.ClearGases) - { - var targetMixture = CreateReplacementMixture(true); - _atmosphere.SetTileMixture(gridEntity, null, targetPos, targetMixture); + if (floorId == elevatorComp.IntermediateFloorId) + { + var targetMixture = CreateReplacementMixture(true); + _atmosphere.SetTileMixture(gridEntity, null, targetPos, targetMixture); + } } } } From 0f8745850194741569b7ca21ebb6555fd326fb9e Mon Sep 17 00:00:00 2001 From: Neyran Date: Sun, 12 Oct 2025 18:53:58 +0300 Subject: [PATCH 10/10] Update ComplexElevatorSystem.cs --- .../_Scp/ComplexElevator/ComplexElevatorSystem.cs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/Content.Server/_Scp/ComplexElevator/ComplexElevatorSystem.cs b/Content.Server/_Scp/ComplexElevator/ComplexElevatorSystem.cs index cdb85c01c74..196b6cd2a66 100644 --- a/Content.Server/_Scp/ComplexElevator/ComplexElevatorSystem.cs +++ b/Content.Server/_Scp/ComplexElevator/ComplexElevatorSystem.cs @@ -178,16 +178,6 @@ private bool IsEntityValidForTeleport(EntityUid entUid, EntityUid elevatorUid, T private bool CanMoveWithEntities(Entity ent) { - var elevatorTransform = Transform(ent.Owner); - var aabb = _lookup.GetWorldAABB(ent.Owner, elevatorTransform); - var intersectingEntities = _lookup.GetEntitiesIntersecting(elevatorTransform.MapID, aabb, LookupFlags.Uncontained); - - foreach (var entUid in intersectingEntities) - { - if (entUid == ent.Owner || HasComp(entUid)) - continue; - } - return GetEntitiesInElevator(ent.Owner).Count(e => !HasComp(e)) <= ent.Comp.MaxEntitiesToTeleport; } @@ -481,7 +471,7 @@ private void KillEntitiesInTargetArea(Entity elevator, foreach (var entUid in intersectingEntities) { - if (IsEntityValidForTeleport(entUid, elevator.Owner)) + if (IsEntityValidForTeleport(entUid, elevator.Owner) && !HasComp(entUid)) { var damage = new DamageSpecifier(); damage.DamageDict["Blunt"] = 1000;