Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a component that can make doors airtight, for player made docking ports & EVA access #2620

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
11 changes: 11 additions & 0 deletions Content.Server/Shuttles/Events/UpdateSpacedEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using Content.Server.Shuttles.Components;

namespace Content.Server.Shuttles.Events;

/// <summary>
/// Raised whenever a tile changes from spaced to unspaced or vice versa.
/// </summary>
public sealed class UpdateSpacedEvent : EntityEventArgs
{

}
32 changes: 32 additions & 0 deletions Content.Server/Shuttles/Systems/ShuttleSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
using Content.Server.Parallax;
using Content.Server.Procedural;
using Content.Server.Shuttles.Components;
using Content.Server.Shuttles.Events; // Frontier
using Content.Server.Station.Systems;
using Content.Server.Stunnable;
using Content.Shared.GameTicking;
using Content.Shared.Mobs.Systems;
using Content.Shared.Shuttles.Systems;
using Content.Shared.Throwing;
using Content.Shared.Maps; // Frontier
using JetBrains.Annotations;
using Robust.Server.GameObjects;
using Robust.Server.GameStates;
Expand Down Expand Up @@ -80,6 +82,7 @@ public override void Initialize()

SubscribeLocalEvent<GridInitializeEvent>(OnGridInit);
SubscribeLocalEvent<FixturesComponent, GridFixtureChangeEvent>(OnGridFixtureChange);
SubscribeLocalEvent<ShuttleComponent, TileChangedEvent>(OnShuttleTileChange); // Frontier

NfInitialize(); // Frontier Initialization for the ShuttleSystem

Expand All @@ -100,6 +103,35 @@ private void OnGridFixtureChange(EntityUid uid, FixturesComponent manager, GridF
}
}

private void OnShuttleTileChange(EntityUid uid, ShuttleComponent component, ref TileChangedEvent args)
{
// Stop checking if the IsSpace didn't change
if (args.NewTile.IsSpace(_tileDefManager) == args.OldTile.IsSpace(_tileDefManager))
return;

var tilePos = args.NewTile.GridIndices;
var grid = Comp<MapGridComponent>(uid);
var xformQuery = GetEntityQuery<TransformComponent>();
var thrusterQuery = GetEntityQuery<ThrusterComponent>();

for (var x = -1; x <= 1; x++)
{
for (var y = -1; y <= 1; y++)
{
if (x != 0 && y != 0)
continue;

var checkPos = tilePos + new Vector2i(x, y);
var enumerator = _mapSystem.GetAnchoredEntitiesEnumerator(uid, grid, checkPos);

while (enumerator.MoveNext(out var ent))
{
RaiseLocalEvent(ent.Value, new UpdateSpacedEvent { });
}
}
}
}

private void OnGridInit(GridInitializeEvent ev)
{
if (HasComp<MapComponent>(ev.EntityUid))
Expand Down
47 changes: 14 additions & 33 deletions Content.Server/Shuttles/Systems/ThrusterSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Content.Server.Power.Components;
using Content.Server.Power.EntitySystems;
using Content.Server.Shuttles.Components;
using Content.Server.Shuttles.Events; // Frontier
using Content.Shared.Damage;
using Content.Shared.Examine;
using Content.Shared.Interaction;
Expand Down Expand Up @@ -56,7 +57,7 @@ public override void Initialize()

SubscribeLocalEvent<ThrusterComponent, ExaminedEvent>(OnThrusterExamine);

SubscribeLocalEvent<ShuttleComponent, TileChangedEvent>(OnShuttleTileChange);
SubscribeLocalEvent<ThrusterComponent, UpdateSpacedEvent>(OnTileChange); // Frontier

SubscribeLocalEvent<ThrusterComponent, RefreshPartsEvent>(OnRefreshParts);
SubscribeLocalEvent<ThrusterComponent, UpgradeExamineEvent>(OnUpgradeExamine);
Expand Down Expand Up @@ -124,42 +125,22 @@ private void OnIsHotEvent(EntityUid uid, ThrusterComponent component, IsHotEvent
args.IsHot = component.Type != ThrusterType.Angular && component.IsOn;
}

private void OnShuttleTileChange(EntityUid uid, ShuttleComponent component, ref TileChangedEvent args)
private void OnTileChange(EntityUid uid, ThrusterComponent component, ref UpdateSpacedEvent args)
{
// If the old tile was space but the new one isn't then disable all adjacent thrusters
if (args.NewTile.IsSpace(_tileDefManager) || !args.OldTile.IsSpace(_tileDefManager))
return;

var tilePos = args.NewTile.GridIndices;
var grid = Comp<MapGridComponent>(uid);
var xformQuery = GetEntityQuery<TransformComponent>();
var thrusterQuery = GetEntityQuery<ThrusterComponent>();
var canEnable = CanEnable(uid, component);

for (var x = -1; x <= 1; x++)
// Enable it if it was turned off but new tile is valid
if (!component.IsOn && canEnable)
{
for (var y = -1; y <= 1; y++)
{
if (x != 0 && y != 0)
continue;

var checkPos = tilePos + new Vector2i(x, y);
var enumerator = _mapSystem.GetAnchoredEntitiesEnumerator(uid, grid, checkPos);

while (enumerator.MoveNext(out var ent))
{
if (!thrusterQuery.TryGetComponent(ent.Value, out var thruster) || !thruster.RequireSpace)
continue;

// Work out if the thruster is facing this direction
var xform = xformQuery.GetComponent(ent.Value);
var direction = xform.LocalRotation.ToWorldVec();

if (new Vector2i((int)direction.X, (int)direction.Y) != new Vector2i(x, y))
continue;
EnableThruster(uid, component);
return;
}

DisableThruster(ent.Value, thruster, xform.GridUid);
}
}
// Disable if new tile invalid
if (component.IsOn && !canEnable)
{
DisableThruster(uid, component);
return;
}
}

Expand Down
18 changes: 18 additions & 0 deletions Content.Server/_NF/Shuttles/Components/AdvDoorSealComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using Content.Shared.Shuttles.Components;
using Content.Server.Shuttles.Systems;

namespace Content.Server.Shuttles.Components
{
[RegisterComponent]
[Access(typeof(AdvDoorSealSystem))]
public sealed partial class AdvDoorSealComponent : Component
{
[DataField, ViewVariables(VVAccess.ReadWrite)]
public bool IsOn { get; set; } = true;

/// <summary>
/// Frontier - Amount of charge this needs from an APC per second to function.
/// </summary>
public float OriginalLoad { get; set; } = 0;
}
}
188 changes: 188 additions & 0 deletions Content.Server/_NF/Shuttles/Systems/AdvDoorSealSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
using Content.Server.Power.Components;
using Content.Server.Power.EntitySystems;
using Content.Server.Shuttles.Components;
using Content.Server.Shuttles.Events;
using Content.Server.Doors.Systems;
using Content.Server.Atmos.Components;
using Content.Server.Atmos.EntitySystems;
using Content.Shared.Examine;
using Content.Shared.Maps;
using Content.Shared.Doors.Components;
using Content.Shared.Localizations;
using Content.Shared.Power;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;

namespace Content.Server.Shuttles.Systems
{

public sealed class AdvDoorSealSystem : EntitySystem
{
[Dependency] private readonly SharedMapSystem _mapSystem = default!;
[Dependency] private readonly ITileDefinitionManager _tileDefManager = default!;
[Dependency] private readonly DoorSystem _doorSystem = default!;
[Dependency] private readonly AirtightSystem _airtightSystem = default!;
public override void Initialize()
{
SubscribeLocalEvent<AdvDoorSealComponent, PowerChangedEvent>(OnPowerChange);
SubscribeLocalEvent<AdvDoorSealComponent, AnchorStateChangedEvent>(OnAnchorChange);
SubscribeLocalEvent<AdvDoorSealComponent, UpdateSpacedEvent>(OnTileChange);
SubscribeLocalEvent<AdvDoorSealComponent, ComponentInit>(OnComponentInit);
SubscribeLocalEvent<AdvDoorSealComponent, ExaminedEvent>(OnDoorExamine);
}

private void OnComponentInit(EntityUid uid, AdvDoorSealComponent component, ComponentInit args)
{
if (TryComp<ApcPowerReceiverComponent>(uid, out var apcPower) && component.OriginalLoad == 0) { component.OriginalLoad = apcPower.Load; }

if (CanEnable(uid, component))
{
EnableAirtightness(uid, component);
}
else
{
DisableAirtightness(uid, component);
}
}

private void OnTileChange(EntityUid uid, AdvDoorSealComponent component, ref UpdateSpacedEvent args)
{
if (CanEnable(uid, component))
{
EnableAirtightness(uid, component);
}
else
{
DisableAirtightness(uid, component);
}
}

private void OnPowerChange(EntityUid uid, AdvDoorSealComponent component, ref PowerChangedEvent args)
{
if (args.Powered && CanEnable(uid, component))
{
EnableAirtightness(uid, component);
}
else
{
DisableAirtightness(uid, component);
}
}

private void OnAnchorChange(EntityUid uid, AdvDoorSealComponent component, ref AnchorStateChangedEvent args)
{
if (args.Anchored && CanEnable(uid, component))
{
EnableAirtightness(uid, component);
}
else
{
DisableAirtightness(uid, component);
}
}


private void OnDoorExamine(EntityUid uid, AdvDoorSealComponent component, ExaminedEvent args)
{
// Powered is already handled by other power components
var enabled = Loc.GetString(component.IsOn ? "adv-door-seal-comp-enabled" : "adv-door-seal-comp-disabled");

using (args.PushGroup(nameof(AdvDoorSealComponent)))
{
args.PushMarkup(enabled);

if (EntityManager.TryGetComponent(uid, out TransformComponent? xform) && xform.Anchored)
{
var doorLocalization = ContentLocalizationManager.FormatDirection(xform.LocalRotation.ToWorldVec().GetDir()).ToLower();
var doorDir = Loc.GetString("adv-door-seal-comp-door-direction",
("direction", doorLocalization));

args.PushMarkup(doorDir);

var exposed = DockExposed(xform);

var doorText =
Loc.GetString(exposed ? "adv-door-seal-comp-door-exposed" : "adv-door-seal-comp-door-not-exposed");

args.PushMarkup(doorText);
}
}
}

/// <summary>
/// Tries to enable the seals and turn it on. If it's already enabled it does nothing.
/// </summary>
public void EnableAirtightness(EntityUid uid, AdvDoorSealComponent component, TransformComponent? xform = null)
{
if (component.IsOn ||
!Resolve(uid, ref xform))
{
return;
}

component.IsOn = true;
if (TryComp(uid, out DoorComponent? door))
door.ChangeAirtight = false;

if (TryComp(uid, out AirtightComponent? airtight))
_airtightSystem.SetAirblocked((uid, airtight), true);
}


public void DisableAirtightness(EntityUid uid, AdvDoorSealComponent component, TransformComponent? xform = null)
{
if (!Resolve(uid, ref xform)) return;
DisableAirtightness(uid, component, xform.GridUid, xform);
}


/// <summary>
/// Tries to disable the seals
/// </summary>
public void DisableAirtightness(EntityUid uid, AdvDoorSealComponent component, EntityUid? gridId, TransformComponent? xform = null)
{
if (!component.IsOn ||
!Resolve(uid, ref xform))
{
return;
}

component.IsOn = false;
if (TryComp(uid, out DoorComponent? door))
{
door.ChangeAirtight = true;
if (door.State == DoorState.Open && TryComp(uid, out AirtightComponent? airtight)) //If the door's open, goodbye air
{
_airtightSystem.SetAirblocked((uid, airtight), false);
}
}

}

public bool CanEnable(EntityUid uid, AdvDoorSealComponent component)
{
var xform = Transform(uid);

if (!xform.Anchored || !this.IsPowered(uid, EntityManager))
{
return false;
}

return DockExposed(xform);
}

private bool DockExposed(TransformComponent xform)
{
if (xform.GridUid == null)
return true;

var (x, y) = xform.LocalPosition + xform.LocalRotation.ToWorldVec();
var mapGrid = Comp<MapGridComponent>(xform.GridUid.Value);
var tile = _mapSystem.GetTileRef(xform.GridUid.Value, mapGrid, new Vector2i((int)Math.Floor(x), (int)Math.Floor(y)));

return tile.Tile.IsSpace();
}

}

}
5 changes: 5 additions & 0 deletions Resources/Locale/en-US/_NF/shuttles/adv-door-seals.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
adv-door-seal-comp-enabled = The airtight seal system is turned [color=green]on[/color].
adv-door-seal-comp-disabled = The airtight seal system is turned [color=red]off[/color].
adv-door-seal-comp-door-direction = The door is facing [color=yellow]{$direction}[/color].
adv-door-seal-comp-door-exposed = The seals are [color=green]exposed[/color] to space.
adv-door-seal-comp-door-not-exposed = The seals are [color=red]not exposed[/color] to space.
Loading