Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions Content.Client/Power/PowerCharge/PowerChargeWindow.xaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<controls:FancyWindow xmlns="https://spacestation14.io"
<controls:FancyWindow xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
MinSize="270 130"
SetSize="360 180">
MinSize="320 190"
SetSize="420 240">
<BoxContainer Margin="4 0" Orientation="Horizontal">
<BoxContainer Orientation="Vertical" HorizontalExpand="True">
<GridContainer Margin="2 0 0 0" Columns="2">
Expand All @@ -24,6 +24,14 @@
<ProgressBar Name="ChargeBar" MaxValue="255">
<Label Name="ChargeText" Margin="4 0" Text="0 %" />
</ProgressBar>
<!-- IH - Start -->
<!-- Station Mass -->
<Label Name="MassTitle" Text="{Loc 'gravity-generator-window-mass'}" StyleClasses="StatusFieldTitle" Visible="False" />
<Label Name="MassValue" Text="&#8212;" Visible="False" />
<!-- FTL -->
<Label Name="FtlTitle" Text="{Loc 'gravity-generator-window-ftl'}" StyleClasses="StatusFieldTitle" Visible="False" />
<Label Name="FtlValue" Text="&#8212;" Visible="False" />
<!-- IH - End -->
</GridContainer>
</BoxContainer>
<PanelContainer Margin="12 0 0 0" StyleClasses="Inset" VerticalAlignment="Center">
Expand Down
48 changes: 47 additions & 1 deletion Content.Client/Power/PowerCharge/PowerChargeWindow.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
using Content.Client.UserInterface.Controls;
using Content.Shared.AWS.Gravity;
using Content.Shared.Power;
using System;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;

namespace Content.Client.Power.PowerCharge;

[GenerateTypedNameReferences]
public sealed partial class PowerChargeWindow : FancyWindow
{
private readonly ButtonGroup _buttonGroup = new();
private readonly IEntityManager _entityManager = IoCManager.Resolve<IEntityManager>();
private EntityUid _owner = EntityUid.Invalid;

public PowerChargeWindow()
{
Expand All @@ -27,6 +33,7 @@ public void UpdateWindow(PowerChargeBoundUserInterface bui, string title)
OffButton.OnPressed += _ => bui.SetPowerSwitch(false);

EntityView.SetEntity(bui.Owner);
_owner = bui.Owner;
}

public void UpdateState(PowerChargeState state)
Expand Down Expand Up @@ -68,5 +75,44 @@ public void UpdateState(PowerChargeState state)
: Loc.GetString("power-charge-window-eta-none");

EtaLabel.SetOnlyStyleClass(state.EtaSeconds >= 0 ? "Caution" : "Disabled");

var showStationStatus = TryGetStationStatus(out var stationMass, out var stationLocked);
MassTitle.Visible = MassValue.Visible = showStationStatus;
FtlTitle.Visible = FtlValue.Visible = showStationStatus;

if (showStationStatus)
{
var roundedMass = Math.Round(stationMass, 1);
MassValue.Text = Loc.GetString("gravity-generator-window-mass-value", ("mass", roundedMass));

var ftlKey = stationLocked ? "gravity-generator-examine-ftl-locked" : "gravity-generator-examine-ftl-free";
FtlValue.Text = Loc.GetString(ftlKey);
FtlValue.SetOnlyStyleClass(stationLocked ? "Danger" : "Good");
}
else
{
MassValue.Text = "\u2014";
FtlValue.Text = "\u2014";
FtlValue.SetOnlyStyleClass("Disabled");
}
}

private bool TryGetStationStatus(out float mass, out bool locked)
{
mass = 0f;
locked = false;

if (!_owner.IsValid())
return false;

if (!_entityManager.TryGetComponent(_owner, out AwsGravityGeneratorStatusComponent? status))
return false;

if (!status.ShowStatus)
return false;

mass = status.StationMass;
locked = status.StationFtlLocked;
return true;
}
}
}
224 changes: 224 additions & 0 deletions Content.Server/AWS/Gravity/AwsGravityGeneratorFieldSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
using System;
using System.Numerics;
using Content.Server.Gravity;
using Content.Server.Power.Components;
using Content.Server.Power.EntitySystems;
using Content.Shared.Gravity;
using Robust.Shared.GameObjects;
using Robust.Shared.Map.Components;
using Robust.Shared.Maths;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Components;
using Robust.Shared.Physics.Systems;

namespace Content.Server.AWS.Gravity;

/// <summary>
/// AWS-specific overrides for gravity generator grid interactions (mass multipliers, FTL blocking, etc.).
/// </summary>
public sealed class AwsGravityGeneratorFieldSystem : EntitySystem
{
[Dependency] private readonly SharedPhysicsSystem _physics = default!;

private EntityQuery<MapGridComponent> _gridQuery = default!;
private EntityQuery<PhysicsComponent> _physicsQuery = default!;
private EntityQuery<GridGravityWellComponent> _gravityWellQuery = default!;
private EntityQuery<FixturesComponent> _fixturesQuery = default!;

public override void Initialize()
{
base.Initialize();
_gridQuery = GetEntityQuery<MapGridComponent>();
_physicsQuery = GetEntityQuery<PhysicsComponent>();
_gravityWellQuery = GetEntityQuery<GridGravityWellComponent>();
_fixturesQuery = GetEntityQuery<FixturesComponent>();

SubscribeLocalEvent<GravityGeneratorComponent, AwsGravityGeneratorParentChangedEvent>(OnParentChanged);
SubscribeLocalEvent<GravityGeneratorComponent, AwsGravityGeneratorActivatedEvent>(OnActivated);
SubscribeLocalEvent<GravityGeneratorComponent, AwsGravityGeneratorDeactivatedEvent>(OnDeactivated);
SubscribeLocalEvent<GravityGeneratorComponent, ComponentShutdown>(OnShutdown);
}

public override void Update(float frameTime)
{
base.Update(frameTime);

var query = EntityQueryEnumerator<GravityGeneratorComponent, PowerChargeComponent>();
while (query.MoveNext(out var uid, out var grav, out var charge))
{
var switchedOn = charge.SwitchedOn;

if (!switchedOn && grav.CurrentGrid is { } offGrid && !grav.GravityActive)
{
DisableField(uid, grav);
}
else if (switchedOn && grav.CurrentGrid is null)
{
TryEnableField(uid, grav);
}

if (grav.CurrentGrid is not { } grid || !_gravityWellQuery.TryGetComponent(grid, out var well))
continue;

var effectiveMultiplier = GetEffectiveMassMultiplier(uid, grav, charge);
if (well.TryUpdateGeneratorMultiplier(uid, effectiveMultiplier))
ApplyGridEffects(grid, well);
}
}

private void OnActivated(Entity<GravityGeneratorComponent> ent, ref AwsGravityGeneratorActivatedEvent args)
{
TryEnableField(ent.Owner, ent.Comp);
}

private void OnDeactivated(Entity<GravityGeneratorComponent> ent, ref AwsGravityGeneratorDeactivatedEvent args)
{
DisableField(ent.Owner, ent.Comp);
}

private void OnShutdown(Entity<GravityGeneratorComponent> ent, ref ComponentShutdown args)
{
DisableField(ent.Owner, ent.Comp);
}

private void OnParentChanged(EntityUid uid, GravityGeneratorComponent component, ref AwsGravityGeneratorParentChangedEvent args)
{
if (!component.GravityActive)
return;

if (args.OldParent != null && args.OldParent.Value == component.CurrentGrid)
RemoveFromGrid(args.OldParent.Value, uid, component);

TryEnableField(uid, component);
}

private void TryEnableField(EntityUid generator, GravityGeneratorComponent component)
{
if (!TryGetParentGrid(generator, out var gridUid))
return;

var well = EnsureComp<GridGravityWellComponent>(gridUid);
var effectiveMultiplier = GetEffectiveMassMultiplier(generator, component);
var blocksFtl = component.GravityActive && component.BlocksFtl;
well.SetGenerator(generator, effectiveMultiplier, component.ProtectRadius, blocksFtl);
ApplyGridEffects(gridUid, well);
component.CurrentGrid = gridUid;

if (component.GravityActive && _physicsQuery.TryGetComponent(gridUid, out var body))
{
_physics.SetLinearVelocity(gridUid, Vector2.Zero, body: body);
_physics.SetAngularVelocity(gridUid, 0f, body: body);
}
}

private void DisableField(EntityUid generator, GravityGeneratorComponent component)
{
if (component.CurrentGrid is not { } grid)
return;

RemoveFromGrid(grid, generator, component);
}

private void RemoveFromGrid(EntityUid gridUid, EntityUid generator, GravityGeneratorComponent component)
{
if (!_gravityWellQuery.TryGetComponent(gridUid, out var well))
{
component.CurrentGrid = null;
return;
}

if (!well.RemoveGenerator(generator))
return;

component.CurrentGrid = null;

ApplyGridEffects(gridUid, well);
if (!well.Active)
RemCompDeferred<GridGravityWellComponent>(gridUid);
}

private bool TryGetParentGrid(EntityUid uid, out EntityUid gridUid)
{
gridUid = EntityUid.Invalid;

if (!TryComp(uid, out TransformComponent? xform))
return false;

var parent = xform.ParentUid;

if (!parent.IsValid())
return false;

if (!_gridQuery.HasComponent(parent))
return false;

gridUid = parent;
return true;
}

private void ApplyGridEffects(EntityUid gridUid, GridGravityWellComponent well)
{
UpdateGridMass(gridUid, well);
Dirty(gridUid, well);
}

private void UpdateGridMass(EntityUid gridUid, GridGravityWellComponent well)
{
if (!_fixturesQuery.TryGetComponent(gridUid, out var fixtures))
{
well.ClearBaseDensities();
return;
}

var targetMultiplier = MathF.Max(1f, well.MassMultiplier);

if (MathHelper.CloseTo(targetMultiplier, 1f))
{
if (!MathHelper.CloseTo(well.AppliedMassMultiplier, 1f))
{
foreach (var (id, fixture) in fixtures.Fixtures)
{
if (!well.TryGetBaseDensity(id, out var baseDensity))
continue;

_physics.SetDensity(gridUid, id, fixture, baseDensity, manager: fixtures);
}
}

well.ClearBaseDensities();
return;
}

foreach (var (id, fixture) in fixtures.Fixtures)
{
if (!well.TryGetBaseDensity(id, out var baseDensity))
{
baseDensity = fixture.Density;
well.RememberBaseDensity(id, baseDensity);
}

_physics.SetDensity(gridUid, id, fixture, baseDensity * targetMultiplier, manager: fixtures);
}

well.AppliedMassMultiplier = targetMultiplier;
}

private float GetEffectiveMassMultiplier(EntityUid generator, GravityGeneratorComponent component, PowerChargeComponent? chargeComp = null)
{
var maxMultiplier = MathF.Max(component.MassMultiplier, 1f);
var chargeLevel = chargeComp?.Charge ??
(TryComp(generator, out PowerChargeComponent? storedCharge) ? storedCharge.Charge : 1f);

chargeLevel = Math.Clamp(chargeLevel, 0f, 1f);
return MathHelper.Lerp(1f, maxMultiplier, chargeLevel);
}

[ByRefEvent]
public readonly record struct AwsGravityGeneratorActivatedEvent(Entity<GravityGeneratorComponent> Generator);

[ByRefEvent]
public readonly record struct AwsGravityGeneratorDeactivatedEvent(Entity<GravityGeneratorComponent> Generator);

[ByRefEvent]
public readonly record struct AwsGravityGeneratorParentChangedEvent(Entity<GravityGeneratorComponent> Generator, EntityUid? OldParent);
}
Loading
Loading