mech air overhaul (#19140)
Co-authored-by: deltanedas <@deltanedas:kde.org>
This commit is contained in:
22
Content.Server/Mech/Components/MechAirFilterComponent.cs
Normal file
22
Content.Server/Mech/Components/MechAirFilterComponent.cs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
using Content.Shared.Atmos;
|
||||||
|
|
||||||
|
namespace Content.Server.Mech.Components;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is basically a reverse scrubber for MechAir
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed class MechAirFilterComponent : Component
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gases that will be filtered out of internal air
|
||||||
|
/// </summary>
|
||||||
|
[DataField("gases", required: true)]
|
||||||
|
public HashSet<Gas> Gases = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Target volume to transfer every second.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("transferRate")]
|
||||||
|
public float TransferRate = MechAirComponent.GasMixVolume * 0.1f;
|
||||||
|
}
|
||||||
28
Content.Server/Mech/Components/MechAirIntakeComponent.cs
Normal file
28
Content.Server/Mech/Components/MechAirIntakeComponent.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
using Content.Shared.Atmos;
|
||||||
|
|
||||||
|
namespace Content.Server.Mech.Components;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is basically a siphon vent for mech but not using pump vent component because MechAir bad
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed class MechAirIntakeComponent : Component
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Target pressure change for a single atmos tick
|
||||||
|
/// </summary>
|
||||||
|
[DataField("targetPressureChange")]
|
||||||
|
public float TargetPressureChange = 5f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// How strong the intake pump is, it will be able to replenish air from lower pressure areas.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("pumpPower")]
|
||||||
|
public float PumpPower = 2f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Pressure to intake gases up to, maintains MechAir pressure.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("pressure")]
|
||||||
|
public float Pressure = Atmospherics.OneAtmosphere;
|
||||||
|
}
|
||||||
81
Content.Server/Mech/Systems/MechSystem.Filtering.cs
Normal file
81
Content.Server/Mech/Systems/MechSystem.Filtering.cs
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
using Content.Server.Atmos;
|
||||||
|
using Content.Server.Atmos.Piping.Components;
|
||||||
|
using Content.Server.Mech.Components;
|
||||||
|
using Content.Shared.Atmos;
|
||||||
|
using Content.Shared.Mech.Components;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
|
||||||
|
namespace Content.Server.Mech.Systems;
|
||||||
|
|
||||||
|
// TODO: this could be reused for gasmask or something if MechAir wasnt a thing
|
||||||
|
public sealed partial class MechSystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||||
|
|
||||||
|
private void InitializeFiltering()
|
||||||
|
{
|
||||||
|
SubscribeLocalEvent<MechAirIntakeComponent, AtmosDeviceUpdateEvent>(OnIntakeUpdate);
|
||||||
|
SubscribeLocalEvent<MechAirFilterComponent, AtmosDeviceUpdateEvent>(OnFilterUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnIntakeUpdate(EntityUid uid, MechAirIntakeComponent intake, AtmosDeviceUpdateEvent args)
|
||||||
|
{
|
||||||
|
if (!TryComp<MechComponent>(uid, out var mech) || !mech.Airtight || !TryComp<MechAirComponent>(uid, out var mechAir))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// if the mech is filled there is nothing to do
|
||||||
|
if (mechAir.Air.Pressure >= intake.Pressure)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var environment = _atmosphere.GetContainingMixture(uid, true, true);
|
||||||
|
// nothing to intake from
|
||||||
|
if (environment == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// absolute maximum pressure change
|
||||||
|
var pressureDelta = args.dt * intake.TargetPressureChange;
|
||||||
|
pressureDelta = MathF.Min(pressureDelta, intake.Pressure - mechAir.Air.Pressure);
|
||||||
|
if (pressureDelta <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// how many moles to transfer to change internal pressure by pressureDelta
|
||||||
|
// ignores temperature difference because lazy
|
||||||
|
var transferMoles = pressureDelta * mechAir.Air.Volume / (environment.Temperature * Atmospherics.R);
|
||||||
|
_atmosphere.Merge(mechAir.Air, environment.Remove(transferMoles));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnFilterUpdate(EntityUid uid, MechAirFilterComponent filter, AtmosDeviceUpdateEvent args)
|
||||||
|
{
|
||||||
|
if (!TryComp<MechComponent>(uid, out var mech) || !mech.Airtight || !TryComp<MechAirComponent>(uid, out var mechAir))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var ratio = MathF.Min(1f, args.dt * filter.TransferRate / mechAir.Air.Volume);
|
||||||
|
var removed = mechAir.Air.RemoveRatio(ratio);
|
||||||
|
// nothing left to remove from the mech
|
||||||
|
if (MathHelper.CloseToPercent(removed.TotalMoles, 0f))
|
||||||
|
return;
|
||||||
|
|
||||||
|
|
||||||
|
var coordinates = Transform(uid).MapPosition;
|
||||||
|
GasMixture? destination = null;
|
||||||
|
if (_map.TryFindGridAt(coordinates, out _, out var grid))
|
||||||
|
{
|
||||||
|
var tile = grid.GetTileRef(coordinates);
|
||||||
|
destination = _atmosphere.GetTileMixture(tile.GridUid, null, tile.GridIndices, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (destination != null)
|
||||||
|
{
|
||||||
|
_atmosphere.ScrubInto(removed, destination, filter.Gases);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// filtering into space/planet so just discard them
|
||||||
|
foreach (var gas in filter.Gases)
|
||||||
|
{
|
||||||
|
removed.SetMoles(gas, 0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_atmosphere.Merge(mechAir.Air, removed);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,17 +24,17 @@ using Robust.Shared.Map;
|
|||||||
namespace Content.Server.Mech.Systems;
|
namespace Content.Server.Mech.Systems;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public sealed class MechSystem : SharedMechSystem
|
public sealed partial class MechSystem : SharedMechSystem
|
||||||
{
|
{
|
||||||
|
[Dependency] private readonly ActionBlockerSystem _actionBlocker = default!;
|
||||||
[Dependency] private readonly AtmosphereSystem _atmosphere = default!;
|
[Dependency] private readonly AtmosphereSystem _atmosphere = default!;
|
||||||
|
[Dependency] private readonly BatterySystem _battery = default!;
|
||||||
[Dependency] private readonly ContainerSystem _container = default!;
|
[Dependency] private readonly ContainerSystem _container = default!;
|
||||||
[Dependency] private readonly DamageableSystem _damageable = default!;
|
[Dependency] private readonly DamageableSystem _damageable = default!;
|
||||||
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
|
|
||||||
[Dependency] private readonly IMapManager _map = default!;
|
[Dependency] private readonly IMapManager _map = default!;
|
||||||
[Dependency] private readonly UserInterfaceSystem _ui = default!;
|
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
|
||||||
[Dependency] private readonly ActionBlockerSystem _actionBlocker = default!;
|
|
||||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||||
[Dependency] private readonly BatterySystem _batterySystem = default!;
|
[Dependency] private readonly UserInterfaceSystem _ui = default!;
|
||||||
|
|
||||||
private ISawmill _sawmill = default!;
|
private ISawmill _sawmill = default!;
|
||||||
|
|
||||||
@@ -45,6 +45,8 @@ public sealed class MechSystem : SharedMechSystem
|
|||||||
|
|
||||||
_sawmill = Logger.GetSawmill("mech");
|
_sawmill = Logger.GetSawmill("mech");
|
||||||
|
|
||||||
|
InitializeFiltering();
|
||||||
|
|
||||||
SubscribeLocalEvent<MechComponent, InteractUsingEvent>(OnInteractUsing);
|
SubscribeLocalEvent<MechComponent, InteractUsingEvent>(OnInteractUsing);
|
||||||
SubscribeLocalEvent<MechComponent, EntInsertedIntoContainerMessage>(OnInsertBattery);
|
SubscribeLocalEvent<MechComponent, EntInsertedIntoContainerMessage>(OnInsertBattery);
|
||||||
SubscribeLocalEvent<MechComponent, MapInitEvent>(OnMapInit);
|
SubscribeLocalEvent<MechComponent, MapInitEvent>(OnMapInit);
|
||||||
@@ -127,11 +129,14 @@ public sealed class MechSystem : SharedMechSystem
|
|||||||
private void OnMapInit(EntityUid uid, MechComponent component, MapInitEvent args)
|
private void OnMapInit(EntityUid uid, MechComponent component, MapInitEvent args)
|
||||||
{
|
{
|
||||||
var xform = Transform(uid);
|
var xform = Transform(uid);
|
||||||
foreach (var ent in component.StartingEquipment.Select(equipment => Spawn(equipment, xform.Coordinates)))
|
// TODO: this should use containerfill?
|
||||||
|
foreach (var equipment in component.StartingEquipment)
|
||||||
{
|
{
|
||||||
|
var ent = Spawn(equipment, xform.Coordinates);
|
||||||
InsertEquipment(uid, ent, component);
|
InsertEquipment(uid, ent, component);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: this should just be damage and battery
|
||||||
component.Integrity = component.MaxIntegrity;
|
component.Integrity = component.MaxIntegrity;
|
||||||
component.Energy = component.MaxEnergy;
|
component.Energy = component.MaxEnergy;
|
||||||
|
|
||||||
@@ -305,56 +310,6 @@ public sealed class MechSystem : SharedMechSystem
|
|||||||
UserInterfaceSystem.SetUiState(ui, state);
|
UserInterfaceSystem.SetUiState(ui, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool TryInsert(EntityUid uid, EntityUid? toInsert, MechComponent? component = null)
|
|
||||||
{
|
|
||||||
if (!Resolve(uid, ref component))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!base.TryInsert(uid, toInsert, component))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (component.Airtight && TryComp(uid, out MechAirComponent? mechAir))
|
|
||||||
{
|
|
||||||
var coordinates = Transform(uid).MapPosition;
|
|
||||||
if (_map.TryFindGridAt(coordinates, out _, out var grid))
|
|
||||||
{
|
|
||||||
var tile = grid.GetTileRef(coordinates);
|
|
||||||
|
|
||||||
if (_atmosphere.GetTileMixture(tile.GridUid, null, tile.GridIndices, true) is { } environment)
|
|
||||||
{
|
|
||||||
_atmosphere.Merge(mechAir.Air, environment.RemoveVolume(MechAirComponent.GasMixVolume));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool TryEject(EntityUid uid, MechComponent? component = null)
|
|
||||||
{
|
|
||||||
if (!Resolve(uid, ref component))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!base.TryEject(uid, component))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (component.Airtight && TryComp(uid, out MechAirComponent? mechAir))
|
|
||||||
{
|
|
||||||
var coordinates = Transform(uid).MapPosition;
|
|
||||||
if (_map.TryFindGridAt(coordinates, out _, out var grid))
|
|
||||||
{
|
|
||||||
var tile = grid.GetTileRef(coordinates);
|
|
||||||
|
|
||||||
if (_atmosphere.GetTileMixture(tile.GridUid, null, tile.GridIndices, true) is { } environment)
|
|
||||||
{
|
|
||||||
_atmosphere.Merge(environment, mechAir.Air);
|
|
||||||
mechAir.Air.Clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void BreakMech(EntityUid uid, MechComponent? component = null)
|
public override void BreakMech(EntityUid uid, MechComponent? component = null)
|
||||||
{
|
{
|
||||||
base.BreakMech(uid, component);
|
base.BreakMech(uid, component);
|
||||||
@@ -378,7 +333,7 @@ public sealed class MechSystem : SharedMechSystem
|
|||||||
if (!TryComp<BatteryComponent>(battery, out var batteryComp))
|
if (!TryComp<BatteryComponent>(battery, out var batteryComp))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
_batterySystem.SetCharge(battery!.Value, batteryComp.CurrentCharge + delta.Float(), batteryComp);
|
_battery.SetCharge(battery!.Value, batteryComp.CurrentCharge + delta.Float(), batteryComp);
|
||||||
if (batteryComp.CurrentCharge != component.Energy) //if there's a discrepency, we have to resync them
|
if (batteryComp.CurrentCharge != component.Energy) //if there's a discrepency, we have to resync them
|
||||||
{
|
{
|
||||||
_sawmill.Debug($"Battery charge was not equal to mech charge. Battery {batteryComp.CurrentCharge}. Mech {component.Energy}");
|
_sawmill.Debug($"Battery charge was not equal to mech charge. Battery {batteryComp.CurrentCharge}. Mech {component.Energy}");
|
||||||
|
|||||||
@@ -406,7 +406,7 @@ public abstract class SharedMechSystem : EntitySystem
|
|||||||
/// <param name="toInsert"></param>
|
/// <param name="toInsert"></param>
|
||||||
/// <param name="component"></param>
|
/// <param name="component"></param>
|
||||||
/// <returns>Whether or not the entity was inserted</returns>
|
/// <returns>Whether or not the entity was inserted</returns>
|
||||||
public virtual bool TryInsert(EntityUid uid, EntityUid? toInsert, MechComponent? component = null)
|
public bool TryInsert(EntityUid uid, EntityUid? toInsert, MechComponent? component = null)
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref component))
|
if (!Resolve(uid, ref component))
|
||||||
return false;
|
return false;
|
||||||
@@ -429,7 +429,7 @@ public abstract class SharedMechSystem : EntitySystem
|
|||||||
/// <param name="uid"></param>
|
/// <param name="uid"></param>
|
||||||
/// <param name="component"></param>
|
/// <param name="component"></param>
|
||||||
/// <returns>Whether or not the pilot was ejected.</returns>
|
/// <returns>Whether or not the pilot was ejected.</returns>
|
||||||
public virtual bool TryEject(EntityUid uid, MechComponent? component = null)
|
public bool TryEject(EntityUid uid, MechComponent? component = null)
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref component))
|
if (!Resolve(uid, ref component))
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -6,6 +6,22 @@
|
|||||||
- type: MobMover
|
- type: MobMover
|
||||||
- type: Mech
|
- type: Mech
|
||||||
- type: MechAir
|
- type: MechAir
|
||||||
|
- type: MechAirFilter
|
||||||
|
# everything except oxygen and nitrogen
|
||||||
|
gases:
|
||||||
|
- 2
|
||||||
|
- 3
|
||||||
|
- 4
|
||||||
|
- 5
|
||||||
|
- 6
|
||||||
|
- 7
|
||||||
|
- 8
|
||||||
|
#- 9 TODO: fusion
|
||||||
|
- type: MechAirIntake
|
||||||
|
# for intake and filter to work
|
||||||
|
- type: AtmosDevice
|
||||||
|
requireAnchored: false
|
||||||
|
joinSystem: true
|
||||||
- type: DoAfter
|
- type: DoAfter
|
||||||
- type: Repairable
|
- type: Repairable
|
||||||
fuelCost: 25
|
fuelCost: 25
|
||||||
|
|||||||
Reference in New Issue
Block a user